191 lines
6 KiB
Python
191 lines
6 KiB
Python
# -*- coding: UTF-8 -*-
|
|
|
|
### Tangled Mind
|
|
### Author: Arthur 'Grizzly' Grisel-Davy
|
|
|
|
from glob import glob
|
|
import random
|
|
import pygame
|
|
import yaml
|
|
from random import randint
|
|
|
|
def fetch_rooms(path):
|
|
"""Fetch all the basic tiles asset from the path.
|
|
Return a dictionary
|
|
"""
|
|
|
|
common_wildcard = '[A-Z]*-*.png'
|
|
unique_wildcard = '?-*.png'
|
|
common_filenames = glob(path+common_wildcard)
|
|
unique_filenames = glob(path+unique_wildcard)
|
|
#print(f"Found {len(common_filenames)} common rooms and {len(unique_filenames)} uniques rooms.")
|
|
|
|
assembly = {'T':[],
|
|
'R':[],
|
|
'D':[],
|
|
'L':[],}
|
|
|
|
for filename in common_filenames:
|
|
label = filename.split("/")[-1].split('-')[0]
|
|
if 'T' in label:
|
|
assembly['D'].append((label,filename))
|
|
if 'R' in label:
|
|
assembly['L'].append((label,filename))
|
|
if 'D' in label:
|
|
assembly['T'].append((label,filename))
|
|
if 'L' in label:
|
|
assembly['R'].append((label,filename))
|
|
|
|
background = glob(path+'*back*')[0]
|
|
|
|
return unique_filenames,assembly,background
|
|
|
|
def check_map(carte):
|
|
"""Function to check if a map is valid i.e. if no two rooms are at the same location
|
|
"""
|
|
positions = []
|
|
for room in carte:
|
|
if room[2] in positions:
|
|
return(False)
|
|
else:
|
|
positions.append(room[2])
|
|
return(True)
|
|
|
|
def enemy_placement(carte):
|
|
""" Generate positions of ennemies in each room by picking random positions and testing
|
|
collisions with the room. Exclude the first room.
|
|
"""
|
|
# Load data
|
|
with open(r'./config.yaml') as file:
|
|
data = yaml.load(file,Loader=yaml.FullLoader)
|
|
room_side = data['room_side']
|
|
wall_size = data['wall_size']
|
|
path_enemy = data['path_enemy']
|
|
img_path = data['texture_path']
|
|
|
|
# Generate usefull values and variables
|
|
carte_positions = [[]]
|
|
positions = []
|
|
enemy_mask = pygame.mask.from_surface(pygame.image.load(img_path+path_enemy).convert_alpha())
|
|
enemy_size = enemy_mask.get_size()
|
|
enemy_center = [int(enemy_size[0]/2),int(enemy_size[1]/2)]
|
|
padding_h = wall_size + int(enemy_size[0]/2)
|
|
padding_v = wall_size + int(enemy_size[1]/2)
|
|
retry = 0
|
|
|
|
for room in carte[1:]:
|
|
retry = 0
|
|
while len(positions) < 3 and retry < 20:
|
|
posx = room[2][0] + randint(padding_h, room_side-padding_h)
|
|
posy = room[2][1] + randint(padding_v, room_side-padding_v)
|
|
|
|
if room[1].overlap(enemy_mask, (posx-enemy_center[0],posy-enemy_center[1])):
|
|
retry+=1
|
|
else:
|
|
#print(f'New enemy at {posx,posy}')
|
|
positions.append((posx,posy))
|
|
carte_positions.append(positions)
|
|
positions = []
|
|
|
|
return carte_positions
|
|
|
|
|
|
def map_generator(n):
|
|
"""Map generator generate a map with a main path of n rooms
|
|
"""
|
|
|
|
with open(r'./config.yaml') as file:
|
|
data = yaml.load(file,Loader=yaml.FullLoader)
|
|
room_side = data['room_side']
|
|
|
|
change_side = {'T':'D','R':'L','D':'T','L':'R'}
|
|
deplacements = {'T':[0,-1],'R':[1,0],'D':[0,1],'L':[-1,0]}
|
|
|
|
unique_filenames,assembly,back_path = fetch_rooms('./maps/rooms/')
|
|
#assembly = {'T/R/D/L':[(label1,path1),(label2,path2),...]}
|
|
|
|
|
|
unique_rooms = {filename.split("/")[-1][0].upper():pygame.image.load(filename).convert_alpha() for filename in unique_filenames}
|
|
|
|
current_label= random.choice(list(unique_rooms.keys()))
|
|
start_room = unique_rooms[current_label]
|
|
|
|
# Place the first room in the list
|
|
positions = []
|
|
position = [0,0]
|
|
mask = pygame.mask.from_surface(start_room)
|
|
carte = [(start_room,mask,position)]
|
|
|
|
open_paths = []
|
|
|
|
|
|
counter = 0
|
|
retry = 0
|
|
while counter <= n:
|
|
|
|
# select the next direction, can't be the direction of arrival
|
|
if len(current_label) > 1:
|
|
dir_next = random.choice(current_label.replace(dir_from,''))
|
|
else:
|
|
dir_next = current_label
|
|
dir_from = ''
|
|
|
|
# stor open paths for later closing
|
|
for other_direction in current_label.replace(dir_from,'').replace(dir_next,''):
|
|
other_dir_from = change_side[other_direction]
|
|
other_position = [a+room_side*b for a,b in zip(position,deplacements[other_direction])]
|
|
open_paths.append((other_dir_from,other_position))
|
|
|
|
# Select the next room
|
|
if counter < n: # The next room is not the final room.
|
|
next_label,next_room = random.choice(assembly[dir_next])
|
|
asset = pygame.image.load(next_room).convert_alpha()
|
|
|
|
else:
|
|
# The next room is the finale room.
|
|
asset = unique_rooms[change_side[dir_next]]
|
|
|
|
mask = pygame.mask.from_surface(asset)
|
|
next_position = [position[0]+room_side*deplacements[dir_next][0],position[1]+room_side*deplacements[dir_next][1]]
|
|
dir_from = change_side[dir_next]
|
|
|
|
# Check if we are not overwriting an existing room and store the current one.
|
|
if next_position not in positions:
|
|
counter += 1
|
|
# Build the map
|
|
carte.append((asset,mask,next_position))
|
|
positions.append(position)
|
|
|
|
# Update the variables for next turn
|
|
current_label = next_label
|
|
position = next_position
|
|
positions.append(position)
|
|
else:
|
|
retry +=1
|
|
if retry > 10:
|
|
raise ValueError("Too much retries")
|
|
|
|
|
|
if not check_map(carte):
|
|
raise ValueError("Invalid Map before closing paths.")
|
|
|
|
#Close all the open paths
|
|
for open_path in open_paths:
|
|
if open_path[1] not in positions:
|
|
room = unique_rooms[open_path[0]]
|
|
mask = pygame.mask.from_surface(room)
|
|
position = open_path[1]
|
|
carte.append((room,mask,position))
|
|
positions.append(position)
|
|
|
|
background = pygame.image.load(back_path).convert()
|
|
|
|
if not check_map(carte):
|
|
raise ValueError("Invalid Map after closing paths.")
|
|
|
|
return(carte,(int(room_side/2),int(room_side/2)),background,)
|
|
|
|
|
|
|
|
|
|
|