# -*- 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,)