extends RefCounted class_name ChessMapGenerator # Room type enum enum RoomType { STARTING, NORMAL, BOSS, FINAL, SHOP, EVENT } # Configuration var min_levels = 6 var max_levels = 12 var min_nodes_per_level = 2 var max_nodes_per_level = 4 var positions_per_level = 7 # How many horizontal positions are available (0-6) var starting_elo = 1000 var final_elo = 2100 # Internal variables var _rng = RandomNumberGenerator.new() var _next_id = 0 func _init(seed_value = null): # Set seed for reproducible maps if needed if seed_value != null: _rng.seed = seed_value else: _rng.randomize() # Main function to generate the map func generate_map(): var nodes = [] var connections = [] _next_id = 0 # Determine the number of levels var num_levels = _rng.randi_range(min_levels, max_levels) # Calculate ELO for each level var elo_step = float(final_elo - starting_elo) / (num_levels - 1) # Create starting node (always at position 3, level 0) var start_node = { "id": _get_next_id(), "type": RoomType.STARTING, "level": 0, "position": Vector2(3, 0), "elo": starting_elo } nodes.append(start_node) # Create final boss node (always at position 3, highest level) var final_node = { "id": _get_next_id(), "type": RoomType.FINAL, "level": num_levels - 1, "position": Vector2(3, num_levels - 1), "elo": final_elo } nodes.append(final_node) # Generate intermediate levels var levels_nodes = {0: [start_node], (num_levels - 1): [final_node]} for level in range(1, num_levels - 1): var level_nodes = [] # Calculate ELO for this level var level_elo = starting_elo + (elo_step * level) # Determine number of nodes for this level var num_nodes = _rng.randi_range(min_nodes_per_level, max_nodes_per_level) # Generate available positions and shuffle them var available_positions = [] for pos in range(positions_per_level): available_positions.append(pos) available_positions.shuffle() # Create nodes for this level for i in range(num_nodes): var node_type = _get_random_room_type(level, num_levels) var node = { "id": _get_next_id(), "type": node_type, "level": level, "position": Vector2(available_positions[i], level), "elo": level_elo } nodes.append(node) level_nodes.append(node) levels_nodes[level] = level_nodes # Connect nodes between levels # First connect starting node to level 1 if levels_nodes.has(1) and levels_nodes[1].size() > 0: var num_connections = min(_rng.randi_range(2, 3), levels_nodes[1].size()) var targets = levels_nodes[1].duplicate() targets.shuffle() for i in range(num_connections): connections.append({ "from": start_node.id, "to": targets[i].id }) # Keep track of which nodes are connected var connected_nodes = [start_node.id] for level in range(1, num_levels - 1): if not levels_nodes.has(level) or not levels_nodes.has(level + 1): continue var current_level_nodes = levels_nodes[level] var next_level_nodes = levels_nodes[level + 1].duplicate() next_level_nodes.shuffle() # For each node in current level that is connected from previous level for node in current_level_nodes: if _is_node_connected_to(node.id, connections): # Add to connected nodes connected_nodes.append(node.id) # Connect to 1-2 nodes in next level if not the final level if level < num_levels - 2: var num_next_connections = _rng.randi_range(1, 2) num_next_connections = min(num_next_connections, next_level_nodes.size()) for i in range(num_next_connections): if i < next_level_nodes.size(): connections.append({ "from": node.id, "to": next_level_nodes[i].id }) # Remove the selected nodes so they aren't picked again for i in range(num_next_connections): if next_level_nodes.size() > 0: next_level_nodes.pop_front() # Connect to final boss if at the level before elif level == num_levels - 2: connections.append({ "from": node.id, "to": final_node.id }) # Remove any nodes that aren't connected var valid_nodes = [] for node in nodes: if connected_nodes.has(node.id) or node.id == final_node.id: valid_nodes.append(node) # Clean up connections to removed nodes var valid_connections = [] for conn in connections: var from_valid = false var to_valid = false for node in valid_nodes: if node.id == conn.from: from_valid = true if node.id == conn.to: to_valid = true if from_valid and to_valid: valid_connections.append(conn) return { "nodes": valid_nodes, "connections": valid_connections, "levels": num_levels, "seed": _rng.seed } func _get_random_room_type(level, total_levels): var boss_chance = 0.1 + (level / float(total_levels) * 0.1) var shop_chance = 0.1 + (level / float(total_levels) * 0.05) var event_chance = 0.05 if level == total_levels - 2: boss_chance += 0.3 var roll = _rng.randf() print("_get_random_room_type ", roll, " ", boss_chance, " ", shop_chance, " ", event_chance) if roll < boss_chance: return RoomType.BOSS elif roll < boss_chance + shop_chance: return RoomType.SHOP elif roll < boss_chance + shop_chance + event_chance: return RoomType.EVENT else: return RoomType.NORMAL func _is_node_connected_to(node_id, connections): for conn in connections: if conn.to == node_id: return true return false func _get_next_id(): var id = _next_id _next_id += 1 return id