77from tale import lang
88from tale .base import Door , Exit , Location
99from tale .charbuilder import PlayerNaming
10+ from tale .coord import Coord
1011from tale .driver import Driver
12+ from tale .dungeon .dungeon import Dungeon
1113from tale .dungeon .dungeon_generator import ItemPopulator , Layout , LayoutGenerator , MobPopulator
1214from tale .items .basic import Money
1315from tale .json_story import JsonStory
@@ -31,10 +33,21 @@ def __init__(self, path = '', layout_generator = LayoutGenerator(), mob_populato
3133 self .item_populator = item_populator
3234 self .max_depth = 5
3335 self .depth = 0
36+ self .dungeon = None # Will be created after init
3437
3538
3639 def init (self , driver : Driver ) -> None :
3740 self .llm_util = driver .llm_util
41+ # Create the dungeon instance BEFORE calling super().init()
42+ self .dungeon = Dungeon (
43+ name = "The Depths" ,
44+ story = self ,
45+ llm_util = self .llm_util ,
46+ layout_generator = self .layout_generator ,
47+ mob_populator = self .mob_populator ,
48+ item_populator = self .item_populator ,
49+ max_depth = self .max_depth
50+ )
3851 super (Story , self ).init (driver )
3952
4053 def init_player (self , player : Player ) -> None :
@@ -104,105 +117,15 @@ def add_zone(self, zone: Zone) -> bool:
104117 return False
105118 if zone .locations != {}:
106119 return True
107- first_zone = len (self ._zones .values ()) == 0
108- zone .size_z = 1
109- layout = self .layout_generator .generate ()
110-
111- rooms = self ._prepare_locations (layout = layout , first_zone = first_zone )
112-
113- self ._describe_rooms (zone = zone , layout = layout , rooms = rooms )
114120
115- self ._connect_locations (layout = layout )
116-
117- mob_spawners = self .mob_populator .populate (zone = zone , layout = layout , story = self )
118- for mob_spawner in mob_spawners :
119- self .world .add_mob_spawner (mob_spawner )
120-
121- item_spawners = self .item_populator .populate (zone = zone , story = self )
122- for item_spawner in item_spawners :
123- self .world .add_item_spawner (item_spawner )
124-
125- if zone .center .z == self .max_depth :
126- self ._generate_boss (zone = zone )
127-
128- if not first_zone :
129- self .layout_generator .spawn_gold (zone = zone )
130-
121+ # Use the dungeon to generate the level
122+ if self .dungeon :
123+ depth = len (self .dungeon .zones )
124+ self .depth = depth
125+ self .dungeon .generate_level (zone , depth = depth )
126+
131127 return True
132-
133- def _describe_rooms (self , zone : Zone , layout : Layout , rooms : list ):
134- described_rooms = []
135- sliced_rooms = []
136- for num in range (0 , len (rooms ), 10 ):
137- sliced_rooms .extend (rooms [num :num + 10 ])
138- for i in range (3 ):
139- described_rooms_slice = self .llm_util .generate_dungeon_locations (zone_info = zone .get_info (), locations = sliced_rooms , depth = self .depth , max_depth = self .max_depth ) # type LocationDescriptionResponse
140- if described_rooms_slice .valid :
141- described_rooms .extend (described_rooms_slice .location_descriptions )
142- sliced_rooms = []
143- break
144- if len (rooms ) != len (described_rooms ):
145- print (f'Rooms list not same length: { len (rooms )} vs { len (described_rooms )} ' )
146- for room in described_rooms :
147- i = 1
148- if zone .get_location (room .name ):
149- # ensure unique names
150- room .name = f'{ room .name } ({ i } )'
151- i += 1
152- location = Location (name = room .name , descr = room .description )
153- location .world_location = list (layout .cells .values ())[room .index ].coord
154- zone .add_location (location = location )
155- self .add_location (zone = zone .name , location = location )
156- return described_rooms
157128
158-
159- def _prepare_locations (self , layout : Layout , first_zone : bool = False ) -> list :
160- index = 0
161- rooms = []
162- for cell in list (layout .cells .values ()):
163- if cell .is_dungeon_entrance :
164- rooms .append (f'{{"index": { index } , "name": "Entrance to dungeon"}}' )
165- if cell .is_entrance :
166- rooms .append (f'{{"index": { index } , "name": "Room with pathway leading up to this level."}}' )
167- elif cell .is_exit :
168- rooms .append (f'{{"index": { index } , "name": "Room with pathway leading down"}}' )
169- elif cell .is_room :
170- rooms .append (f'{{"index": { index } , "name": "Room"}}' )
171- else :
172- rooms .append (f'{{"index": { index } , "name": "Hallway", "description": "A hallway"}}' )
173- index += 1
174- return rooms
175-
176- def _connect_locations (self , layout : Layout ) -> None :
177- connections = layout .connections
178- for connection in connections :
179- cell_location = self .world ._grid .get (connection .coord .as_tuple (), None ) # type: Location
180- parent_location = self .world ._grid .get (connection .other .as_tuple (), None ) # type: Location
181- if cell_location .exits .get (parent_location .name , None ):
182- continue
183- elif parent_location .exits .get (cell_location .name , None ):
184- continue
185- if connection .door :
186- Door .connect (cell_location , parent_location .name , '' , None , parent_location , cell_location .name , '' , None , opened = False , locked = connection .locked , key_code = connection .key_code )
187- else :
188- Exit .connect (cell_location , parent_location .name , '' , None , parent_location , cell_location .name , '' , None )
189-
190- def _generate_boss (self , zone : Zone ) -> bool :
191- character = self .llm_util .generate_character (keywords = ['final boss' ]) # Characterv2
192- if character :
193- boss = RoamingMob (character .name ,
194- gender = character .gender ,
195- title = lang .capital (character .name ),
196- descr = character .description ,
197- short_descr = character .appearance ,
198- age = character .age ,
199- personality = character .personality )
200- boss .aliases = [character .name .split (' ' )[0 ]]
201- boss .stats .level = self .max_depth
202- location = random .choice (list (zone .locations .values ()))
203- location .insert (boss , None )
204- return True
205- return False
206129
207130if __name__ == "__main__" :
208131 # story is invoked as a script, start it in the Tale Driver.
0 commit comments