mirror of
				https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
				synced 2025-11-04 08:35:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			702 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
			
		
		
	
	
			702 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
class_name LevelEditor
 | 
						|
extends Node
 | 
						|
 | 
						|
const CAM_MOVE_SPEED_SLOW := 128
 | 
						|
const CAM_MOVE_SPEED_FAST := 256
 | 
						|
 | 
						|
var cursor_tile_position := Vector2i.ZERO
 | 
						|
 | 
						|
const CURSOR_OFFSET := Vector2(-8, -8)
 | 
						|
 | 
						|
var mode := 0
 | 
						|
var current_entity_selector: EditorTileSelector = null
 | 
						|
var current_entity_scene: PackedScene = null
 | 
						|
var current_spawn_offset := Vector2i.ZERO
 | 
						|
var current_tile_source := 0
 | 
						|
var current_tile_coords := Vector2i.ZERO
 | 
						|
var current_tile_flip := Vector2.ZERO ## 1 = true, 0 = false, x = hori, y = vert
 | 
						|
 | 
						|
var menu_open := false
 | 
						|
var testing_level := false
 | 
						|
var entity_tiles := [{}, {}, {}, {}, {}]
 | 
						|
 | 
						|
static var playing_level := false
 | 
						|
 | 
						|
var tile_list: Array[EditorTileSelector] = []
 | 
						|
 | 
						|
var tile_offsets := {}
 | 
						|
 | 
						|
signal level_start
 | 
						|
 | 
						|
var selected_tile_index := 0
 | 
						|
 | 
						|
var can_move_cam := true
 | 
						|
 | 
						|
var music_track_list: Array[String] = [ "res://Assets/Audio/BGM/Silence.json","res://Assets/Audio/BGM/Athletic.json", "res://Assets/Audio/BGM/Autumn.json", "res://Assets/Audio/BGM/Beach.json", "res://Assets/Audio/BGM/Bonus.json", "res://Assets/Audio/BGM/Bowser.json", "res://Assets/Audio/BGM/FinalBowser.json", "res://Assets/Audio/BGM/Castle.json", "res://Assets/Audio/BGM/CoinHeaven.json", "res://Assets/Audio/BGM/Desert.json", "res://Assets/Audio/BGM/Garden.json", "res://Assets/Audio/BGM/GhostHouse.json", "res://Assets/Audio/BGM/Jungle.json", "res://Assets/Audio/BGM/Mountain.json", "res://Assets/Audio/BGM/Overworld.json", "res://Assets/Audio/BGM/Pipeland.json", "res://Assets/Audio/BGM/BooRace.json", "res://Assets/Audio/BGM/Sky.json", "res://Assets/Audio/BGM/Snow.json", "res://Assets/Audio/BGM/Space.json", "res://Assets/Audio/BGM/Underground.json", "res://Assets/Audio/BGM/Underwater.json", "res://Assets/Audio/BGM/Volcano.json", "res://Assets/Audio/BGM/Airship.json"]
 | 
						|
var music_track_names: Array[String] = ["BGM_NONE", "BGM_ATHLETIC", "BGM_AUTUMN", "BGM_BEACH", "BGM_BONUS", "BGM_BOWSER", "BGM_FINALBOWSER", "BGM_CASTLE", "BGM_COINHEAVEN", "BGM_DESERT", "BGM_GARDEN", "BGM_GHOSTHOUSE", "BGM_JUNGLE", "BGM_MOUNTAIN", "BGM_OVERWORLD", "BGM_PIPELAND", "BGM_RACE", "BGM_SKY", "BGM_SNOW", "BGM_SPACE", "BGM_UNDERGROUND", "BGM_UNDERWATER", "BGM_VOLCANO", "BGM_AIRSHIP"]
 | 
						|
 | 
						|
 | 
						|
var bgm_id := 0
 | 
						|
 | 
						|
const MUSIC_TRACK_DIR := "res://Assets/Audio/BGM/"
 | 
						|
 | 
						|
var select_start := Vector2i.ZERO
 | 
						|
var select_end := Vector2i.ZERO
 | 
						|
 | 
						|
signal close_confirm(save: bool)
 | 
						|
 | 
						|
var sub_level_id := 0
 | 
						|
 | 
						|
const BLANK_FILE := {"Info": {}, "Levels": [{}, {}, {}, {}, {}]}
 | 
						|
 | 
						|
static var level_file = {"Info": {}, "Levels": [{}, {}, {}, {}, {}]}
 | 
						|
 | 
						|
var current_layer := 0
 | 
						|
@onready var tile_layer_nodes: Array[TileMapLayer] = [%TileLayer1, %TileLayer2, %TileLayer3, %TileLayer4, %TileLayer5]
 | 
						|
@onready var entity_layer_nodes := [%EntityLayer1, %EntityLayer2, %EntityLayer3, %EntityLayer4, %EntityLayer5]
 | 
						|
var saved_entity_layers := [null, null, null, null, null]
 | 
						|
 | 
						|
var copied_node: Node = null
 | 
						|
var copied_tile_offset := Vector2.ZERO
 | 
						|
var copied_tile_source_id := -1
 | 
						|
var copied_tile_atlas_coors := Vector2i.ZERO
 | 
						|
var copied_tile_terrain_id := -1
 | 
						|
 | 
						|
 | 
						|
const CURSOR_ERASOR := preload("uid://d0j1my4kuapgb")
 | 
						|
const CURSOR_PEN = preload("uid://bt0brcjv0efmw")
 | 
						|
const CURSOR_PENCIL = preload("uid://c8oyhfvlv2gvh")
 | 
						|
const CURSOR_RULER = preload("uid://cg2wkxnmjgplf")
 | 
						|
const CURSOR_INSPECT = preload("uid://1l3foyjqeej")
 | 
						|
 | 
						|
var multi_selecting := false
 | 
						|
 | 
						|
var inspect_mode := false
 | 
						|
var inspect_menu_open := false
 | 
						|
var current_inspect_tile: Node = null
 | 
						|
 | 
						|
var selection_filter := ""
 | 
						|
 | 
						|
static var level_author := ""
 | 
						|
static var level_desc := ""
 | 
						|
static var level_name := ""
 | 
						|
static var difficulty := 0
 | 
						|
 | 
						|
var current_terrain_id := 0
 | 
						|
 | 
						|
static var load_play := false
 | 
						|
 | 
						|
signal tile_selected(tile_selector: EditorTileSelector)
 | 
						|
 | 
						|
var tile_menu_open := false
 | 
						|
 | 
						|
signal editor_start
 | 
						|
 | 
						|
enum EditorState{IDLE, TILE_MENU, MODIFYING_TILE, SAVE_MENU, SELECTING_TILE_SCENE, QUITTING, PLAYTESTING, TRACK_EDITING}
 | 
						|
 | 
						|
var current_state := EditorState.IDLE
 | 
						|
 | 
						|
static var play_pipe_transition := false
 | 
						|
static var play_door_transition := false
 | 
						|
 | 
						|
const BOUNDARY_CONNECT_TILE := Vector2i.ZERO
 | 
						|
 | 
						|
var undo_redo = UndoRedo.new()
 | 
						|
 | 
						|
func _ready() -> void:
 | 
						|
	$TileMenu.hide()
 | 
						|
	DiscordManager.set_discord_status("In The Level Editor...")
 | 
						|
	Global.level_editor = self
 | 
						|
	playing_level = false
 | 
						|
	menu_open = $TileMenu.visible
 | 
						|
	Global.get_node("GameHUD").hide()
 | 
						|
	Global.can_time_tick = false
 | 
						|
	for i in get_tree().get_nodes_in_group("Selectors"):
 | 
						|
		tile_list.append(i)
 | 
						|
	var idx := 0
 | 
						|
	for i in music_track_list:
 | 
						|
		if i == "": continue
 | 
						|
		$%LevelMusic.add_item(tr(music_track_names[idx]).to_upper())
 | 
						|
		idx += 1
 | 
						|
	await get_tree().process_frame
 | 
						|
	Level.start_level_path = scene_file_path
 | 
						|
	var layer_idx := 0
 | 
						|
	for i in entity_layer_nodes:
 | 
						|
		for x in i.get_children():
 | 
						|
			entity_tiles[layer_idx][x.get_meta("tile_position")] = x
 | 
						|
	if level_file != {}:
 | 
						|
		Level.can_set_time = true
 | 
						|
		$LevelLoader.load_level(Checkpoint.sublevel_id)
 | 
						|
		if Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
 | 
						|
			$Info.hide()
 | 
						|
			%Grid.hide()
 | 
						|
			play_level()
 | 
						|
			_physics_process(0)
 | 
						|
			set_physics_process(false)
 | 
						|
			for i in [$TileMenu]:
 | 
						|
				i.queue_free()
 | 
						|
		else:
 | 
						|
			Global.current_game_mode = Global.GameMode.LEVEL_EDITOR
 | 
						|
	else:
 | 
						|
		Global.current_game_mode = Global.GameMode.LEVEL_EDITOR
 | 
						|
	for i: Player in get_tree().get_nodes_in_group("Players"):
 | 
						|
		i.recenter_camera()
 | 
						|
	%LevelName.text = level_name
 | 
						|
	%LevelAuthor.text = level_author
 | 
						|
	%Description.text = level_desc
 | 
						|
 | 
						|
 | 
						|
func _physics_process(delta: float) -> void:
 | 
						|
	if current_state == EditorState.IDLE:
 | 
						|
		handle_tile_cursor()
 | 
						|
	if [EditorState.IDLE, EditorState.TRACK_EDITING].has(current_state):
 | 
						|
		handle_camera(delta)
 | 
						|
	if is_instance_valid(%ThemeName):
 | 
						|
		%ThemeName.text = Global.level_theme
 | 
						|
	handle_hud()
 | 
						|
	if Input.is_action_just_pressed("editor_open_menu"):
 | 
						|
		if current_state == EditorState.IDLE:
 | 
						|
			open_tile_menu()
 | 
						|
		elif current_state == EditorState.TILE_MENU:
 | 
						|
			close_tile_menu()
 | 
						|
	if Input.is_action_just_pressed("editor_play") and (current_state == EditorState.IDLE or current_state == EditorState.PLAYTESTING) and Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
 | 
						|
		Checkpoint.passed_checkpoints.clear()
 | 
						|
		if current_state == EditorState.PLAYTESTING:
 | 
						|
			stop_testing()
 | 
						|
		else:
 | 
						|
			play_level()
 | 
						|
	handle_layers()
 | 
						|
 | 
						|
func handle_hud() -> void:
 | 
						|
	$TileCursor.visible = current_state == EditorState.IDLE
 | 
						|
	$Info.visible = not playing_level
 | 
						|
	%Grid.visible = not playing_level
 | 
						|
 | 
						|
func quit_editor() -> void:
 | 
						|
	%QuitDialog.show()
 | 
						|
 | 
						|
signal level_saved
 | 
						|
 | 
						|
func open_tile_menu() -> void:
 | 
						|
	$TileMenu.visible = true
 | 
						|
	current_state = EditorState.TILE_MENU
 | 
						|
	for i in get_tree().get_nodes_in_group("Selectors"):
 | 
						|
		i.disabled = false
 | 
						|
		i.update_visuals()
 | 
						|
 | 
						|
func close_tile_menu() -> void:
 | 
						|
	$TileMenu.visible = false
 | 
						|
	current_state = EditorState.IDLE
 | 
						|
	for i in get_tree().get_nodes_in_group("Selectors"):
 | 
						|
		i.disabled = false
 | 
						|
 | 
						|
func save_level_before_exit() -> void:
 | 
						|
	tile_menu_open = true
 | 
						|
	open_save_dialog()
 | 
						|
	await level_saved
 | 
						|
	go_back_to_menu()
 | 
						|
 | 
						|
func copy_node(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	if tile_layer_nodes[current_layer].get_used_cells().has(tile_position):
 | 
						|
		var terrain_id = BetterTerrain.get_cell(tile_layer_nodes[current_layer], tile_position)
 | 
						|
		if terrain_id != -2:
 | 
						|
			copied_tile_terrain_id = terrain_id
 | 
						|
			return
 | 
						|
		mode = 0
 | 
						|
		copied_tile_source_id = tile_layer_nodes[current_layer].get_cell_source_id(tile_position)
 | 
						|
		copied_tile_atlas_coors = tile_layer_nodes[current_layer].get_cell_atlas_coords(tile_position)
 | 
						|
	elif entity_tiles[current_layer].has(tile_position):
 | 
						|
		copied_node = entity_tiles[current_layer][tile_position].duplicate()
 | 
						|
		copied_tile_offset = entity_tiles[current_layer][tile_position].get_meta("tile_offset")
 | 
						|
 | 
						|
func cut_node(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	var old_copy = copied_node
 | 
						|
	copy_node(tile_position)
 | 
						|
	if copied_node != old_copy:
 | 
						|
		remove_tile(tile_position)
 | 
						|
 | 
						|
func paste_node(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	place_tile(tile_position, true)
 | 
						|
 | 
						|
func go_back_to_menu() -> void:
 | 
						|
	Global.transition_to_scene("res://Scenes/Levels/CustomLevelMenu.tscn")
 | 
						|
 | 
						|
func open_bindings_menu() -> void:
 | 
						|
	$TileMenu/EditorKeybindsView.open()
 | 
						|
	current_state = EditorState.SAVE_MENU
 | 
						|
	await $TileMenu/EditorKeybindsView.closed
 | 
						|
	current_state = EditorState.TILE_MENU
 | 
						|
 | 
						|
func open_save_dialog() -> void:
 | 
						|
	current_state = EditorState.SAVE_MENU
 | 
						|
	can_move_cam = false
 | 
						|
	%SaveLevelDialog.show()
 | 
						|
	menu_open = true
 | 
						|
 | 
						|
func stop_testing() -> void:
 | 
						|
	cleanup()
 | 
						|
	return_to_editor()
 | 
						|
	
 | 
						|
 | 
						|
func cleanup() -> void:
 | 
						|
	get_tree().paused = false
 | 
						|
	Global.p_switch_timer = 0
 | 
						|
	Global.cancel_score_tally()
 | 
						|
	playing_level = !playing_level
 | 
						|
	play_pipe_transition = false
 | 
						|
	play_door_transition = false
 | 
						|
	LevelPersistance.reset_states()
 | 
						|
	KeyItem.total_collected = 0
 | 
						|
	Global.get_node("GameHUD").visible = playing_level
 | 
						|
	Global.p_switch_active = false
 | 
						|
	if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
 | 
						|
		Global.time = $Level.time_limit
 | 
						|
	elif Level.can_set_time and playing_level:
 | 
						|
		Global.time = $Level.time_limit
 | 
						|
	Global.can_time_tick = playing_level
 | 
						|
	print(Global.can_time_tick)
 | 
						|
 | 
						|
func update_music() -> void:
 | 
						|
	if music_track_list[bgm_id] != "":
 | 
						|
		$Level.music = load(music_track_list[bgm_id].replace(".remap", ""))
 | 
						|
	else:
 | 
						|
		$Level.music = null
 | 
						|
 | 
						|
func play_level() -> void:
 | 
						|
	$TileMenu.hide()
 | 
						|
	menu_open = false
 | 
						|
	update_music()
 | 
						|
	reset_values_for_play()
 | 
						|
	%Camera.enabled = false
 | 
						|
	level_start.emit()
 | 
						|
	get_tree().call_group("Players", "editor_level_start")
 | 
						|
	parse_tiles()
 | 
						|
	if Global.current_game_mode != Global.GameMode.CUSTOM_LEVEL:
 | 
						|
		level_file = await $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
 | 
						|
	current_state = EditorState.PLAYTESTING
 | 
						|
	handle_hud()
 | 
						|
 | 
						|
func parse_tiles() -> void:
 | 
						|
	saved_entity_layers = [null, null, null, null, null]
 | 
						|
	var idx := 0
 | 
						|
	for i in entity_layer_nodes:
 | 
						|
		if is_instance_valid(i) == false:
 | 
						|
			continue
 | 
						|
		if load_play == false:
 | 
						|
			saved_entity_layers[idx] = i.duplicate(DUPLICATE_USE_INSTANTIATION)
 | 
						|
		if i is Player:
 | 
						|
			i.direction = 1
 | 
						|
			i.velocity = Vector2.ZERO
 | 
						|
			i.global_position = i.global_position.snapped(Vector2(8, 8))
 | 
						|
		i.ready.emit()
 | 
						|
		i.set_process_mode(Node.PROCESS_MODE_INHERIT)
 | 
						|
		idx += 1
 | 
						|
 | 
						|
func return_to_editor() -> void:
 | 
						|
	AudioManager.stop_all_music()
 | 
						|
	$Level.music = null
 | 
						|
	%Camera.global_position = get_viewport().get_camera_2d().get_screen_center_position()
 | 
						|
	%Camera.reset_physics_interpolation()
 | 
						|
	return_editor_tiles()
 | 
						|
	%Camera.enabled = true
 | 
						|
	%Camera.make_current()
 | 
						|
	KeyItem.total_collected = 0
 | 
						|
	Door.unlocked_doors.clear()
 | 
						|
	editor_start.emit()
 | 
						|
	current_state = EditorState.IDLE
 | 
						|
	handle_hud()
 | 
						|
 | 
						|
func return_editor_tiles() -> void:
 | 
						|
	for i in entity_layer_nodes:
 | 
						|
		i.queue_free()
 | 
						|
	var idx := 0
 | 
						|
	for i in entity_tiles:
 | 
						|
		i.clear()
 | 
						|
		$Level.add_child(saved_entity_layers[idx])
 | 
						|
		entity_layer_nodes[idx] = saved_entity_layers[idx]
 | 
						|
		idx += 1
 | 
						|
	var layer_idx = 0
 | 
						|
	for x in entity_layer_nodes:
 | 
						|
		x.process_mode = PROCESS_MODE_DISABLED
 | 
						|
		for i in x.get_children():
 | 
						|
			i.owner = self
 | 
						|
			var _tile_position = (Vector2i(i.global_position) - Vector2i(8, 8)) / 16
 | 
						|
			entity_tiles[layer_idx].set(i.get_meta("tile_position", Vector2i.ZERO), i)
 | 
						|
		layer_idx += 1
 | 
						|
 | 
						|
func handle_camera(delta: float) -> void:
 | 
						|
	var input_vector = Input.get_vector("editor_cam_left", "editor_cam_right", "editor_cam_up", "editor_cam_down")
 | 
						|
	%Camera.global_position += input_vector * (CAM_MOVE_SPEED_FAST if Input.is_action_pressed("editor_cam_fast") else CAM_MOVE_SPEED_SLOW) * delta
 | 
						|
	%Camera.global_position.y = clamp(%Camera.global_position.y, $Level.vertical_height + (get_viewport().get_visible_rect().size.y / 2), 32 - (get_viewport().get_visible_rect().size.y / 2))
 | 
						|
	%Camera.global_position.x = clamp(%Camera.global_position.x, -256 + (get_viewport().get_visible_rect().size.x / 2), INF)
 | 
						|
 | 
						|
func handle_layers() -> void:
 | 
						|
	if Input.is_action_just_pressed("layer_up"):
 | 
						|
		current_layer += 1
 | 
						|
	if Input.is_action_just_pressed("layer_down"):
 | 
						|
		current_layer -= 1
 | 
						|
	current_layer = clamp(current_layer, 0, entity_layer_nodes.size() - 1)
 | 
						|
	var idx := 0
 | 
						|
	for i in entity_layer_nodes:
 | 
						|
		i.z_index = 0 if current_layer == idx or playing_level else -1
 | 
						|
		i.modulate = Color(1, 1, 1, 1) if current_layer == idx or playing_level else Color(1, 1, 1, 0.5)
 | 
						|
		tile_layer_nodes[idx].modulate = i.modulate
 | 
						|
		tile_layer_nodes[idx].z_index = i.z_index - 1
 | 
						|
		%LayerDisplay.get_child(idx).modulate = Color.WHITE if current_layer == idx else Color(0.1, 0.1, 0.1, 0.5)
 | 
						|
		idx += 1
 | 
						|
	%LayerLabel.text = "Layer " + str(current_layer + 1)
 | 
						|
 | 
						|
func save_level() -> void:
 | 
						|
	level_author = %LevelAuthor.text
 | 
						|
	level_desc = %Description.text
 | 
						|
	level_name = %LevelName.text
 | 
						|
	difficulty = %DifficultySlider.value
 | 
						|
	var file_name = level_name.to_pascal_case() + ".lvl"
 | 
						|
	%SaveLevelDialog.hide()
 | 
						|
	menu_open = false
 | 
						|
	level_file = $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
 | 
						|
	$LevelSaver.write_file(level_file, file_name)
 | 
						|
	%SaveDialog.text = str("'") +  file_name + "'" + " Saved." 
 | 
						|
	%SaveAnimation.play("Show")
 | 
						|
	current_state = EditorState.TILE_MENU
 | 
						|
	level_saved.emit()
 | 
						|
 | 
						|
func close_save_menu() -> void:
 | 
						|
	can_move_cam = true
 | 
						|
	%SaveLevelDialog.hide()
 | 
						|
	menu_open = false
 | 
						|
	current_state = EditorState.TILE_MENU
 | 
						|
 | 
						|
func handle_tile_cursor() -> void:
 | 
						|
	var target_mouse_icon = null
 | 
						|
	var snapped_position = ((%TileCursor.get_global_mouse_position() - CURSOR_OFFSET).snapped(Vector2(16, 16))) + CURSOR_OFFSET
 | 
						|
	%TileCursor.global_position = (snapped_position)
 | 
						|
	var old_index := selected_tile_index
 | 
						|
	var tile_position = global_position_to_tile_position(snapped_position + Vector2(-8, -8))
 | 
						|
	tile_position.y = clamp(tile_position.y, -30, 1)
 | 
						|
	tile_position.x = clamp(tile_position.x, -16, INF)
 | 
						|
	cursor_tile_position = tile_position
 | 
						|
 | 
						|
	inspect_mode = Input.is_action_pressed("editor_inspect") and not multi_selecting
 | 
						|
	if inspect_mode and current_state == EditorState.IDLE:
 | 
						|
		handle_inspection(tile_position)
 | 
						|
		return
 | 
						|
	
 | 
						|
	if Input.is_action_pressed("mb_left"):
 | 
						|
		if Input.is_action_pressed("editor_select") and not multi_selecting:
 | 
						|
			multi_select_start(tile_position)
 | 
						|
		elif Input.is_action_pressed("editor_select") == false:
 | 
						|
			multi_selecting = false
 | 
						|
			place_tile(tile_position)
 | 
						|
			target_mouse_icon = (CURSOR_PENCIL)
 | 
						|
		
 | 
						|
	if Input.is_action_pressed("mb_right"):
 | 
						|
		if Input.is_action_pressed("editor_select") and not multi_selecting:
 | 
						|
			multi_select_start(tile_position)
 | 
						|
			target_mouse_icon = (CURSOR_RULER)
 | 
						|
		elif Input.is_action_pressed("editor_select") == false:
 | 
						|
			multi_selecting = false
 | 
						|
			remove_tile(tile_position)
 | 
						|
			target_mouse_icon = (CURSOR_ERASOR)
 | 
						|
	
 | 
						|
	if current_state == EditorState.IDLE:
 | 
						|
		if Input.is_action_just_pressed("scroll_up"):
 | 
						|
			selected_tile_index -= 1
 | 
						|
		if Input.is_action_just_pressed("scroll_down"):
 | 
						|
			selected_tile_index += 1
 | 
						|
	
 | 
						|
		if Input.is_action_just_pressed("editor_copy"):
 | 
						|
			copy_node(tile_position)
 | 
						|
		elif Input.is_action_just_pressed("editor_cut"):
 | 
						|
			cut_node(tile_position)
 | 
						|
		elif Input.is_action_pressed("ui_paste"):
 | 
						|
			paste_node(tile_position)
 | 
						|
	
 | 
						|
		if Input.is_action_just_pressed("pick_tile"):
 | 
						|
			pick_tile(tile_position)
 | 
						|
	
 | 
						|
	handle_multi_selecting(tile_position)
 | 
						|
	if old_index != selected_tile_index:
 | 
						|
		selected_tile_index = wrap(selected_tile_index, 0, tile_list.size())
 | 
						|
		on_tile_selected(tile_list[selected_tile_index])
 | 
						|
		show_scroll_preview()
 | 
						|
	
 | 
						|
	Input.set_custom_mouse_cursor(target_mouse_icon)
 | 
						|
 | 
						|
func pick_tile(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	if tile_layer_nodes[current_layer].get_used_cells().has(tile_position):
 | 
						|
		var terrain_id = BetterTerrain.get_cell(tile_layer_nodes[current_layer], tile_position)
 | 
						|
		if terrain_id != -2:
 | 
						|
			mode = 2
 | 
						|
			current_terrain_id = terrain_id
 | 
						|
			return
 | 
						|
		mode = 0
 | 
						|
		current_tile_source = tile_layer_nodes[current_layer].get_cell_source_id(tile_position)
 | 
						|
		current_tile_coords = tile_layer_nodes[current_layer].get_cell_atlas_coords(tile_position)
 | 
						|
	elif entity_tiles[current_layer].has(tile_position) and entity_tiles[current_layer][tile_position] is not Player:
 | 
						|
		mode = 1
 | 
						|
		current_entity_scene = load(entity_tiles[current_layer][tile_position].scene_file_path)
 | 
						|
		current_spawn_offset = entity_tiles[current_layer][tile_position].get_meta("tile_offset")
 | 
						|
 | 
						|
func handle_inspection(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	Input.set_custom_mouse_cursor(CURSOR_INSPECT)
 | 
						|
	if Input.is_action_just_pressed("mb_left"):
 | 
						|
		if entity_tiles[current_layer].get(tile_position) != null:
 | 
						|
			open_tile_properties(entity_tiles[current_layer][tile_position])
 | 
						|
 | 
						|
func open_tile_properties(tile: Node2D) -> void:
 | 
						|
	var properties = get_tile_properties(tile)
 | 
						|
	if properties.is_empty():
 | 
						|
		return
 | 
						|
	
 | 
						|
	current_inspect_tile = tile
 | 
						|
	%TileModifierMenu.override_scenes = tile.get_node("EditorPropertyExposer").properties_force_selector
 | 
						|
	%TileModifierMenu.properties = properties
 | 
						|
	%TileModifierMenu.editing_node = current_inspect_tile
 | 
						|
	%TileModifierMenu.open()
 | 
						|
	current_state = EditorState.MODIFYING_TILE
 | 
						|
	%TileModifierMenu.position = tile.get_global_transform_with_canvas().origin
 | 
						|
	%TileModifierMenu.position.x = clamp(%TileModifierMenu.position.x, 0, get_viewport().get_visible_rect().size.x - %TileModifierMenu.size.x - 2)
 | 
						|
	%TileModifierMenu.position.y = clamp(%TileModifierMenu.position.y, 0, get_viewport().get_visible_rect().size.y - %TileModifierMenu.size.y - 2)
 | 
						|
 | 
						|
	await %TileModifierMenu.closed
 | 
						|
	current_state = EditorState.IDLE
 | 
						|
 | 
						|
func multi_select_start(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	select_start = tile_position
 | 
						|
	multi_selecting = true
 | 
						|
 | 
						|
func handle_multi_selecting(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	select_end = tile_position
 | 
						|
	%MultiSelectRect.visible = multi_selecting
 | 
						|
	var top_corner := select_start
 | 
						|
	if select_start.x > select_end.x:
 | 
						|
		top_corner.x = select_end.x
 | 
						|
	if select_start.y > select_end.y:
 | 
						|
		top_corner.y = select_end.y
 | 
						|
	%MultiSelectRect.global_position = top_corner * 16
 | 
						|
	%MultiSelectRect.size = abs(select_end - select_start) * 16 + Vector2i(16, 16)
 | 
						|
	if multi_selecting:
 | 
						|
		Input.set_custom_mouse_cursor(CURSOR_RULER)
 | 
						|
		if Input.is_action_just_released("mb_left"): 
 | 
						|
			for x in abs(select_end.x - select_start.x) + 1:
 | 
						|
				for y in abs(select_end.y - select_start.y) + 1:
 | 
						|
					var position = top_corner + Vector2i(x, y)
 | 
						|
					place_tile(position)
 | 
						|
			multi_selecting = false
 | 
						|
		if Input.is_action_just_released("mb_right"): 
 | 
						|
			for x in abs(select_end.x - select_start.x) + 1:
 | 
						|
				for y in abs(select_end.y - select_start.y) + 1:
 | 
						|
					var position = top_corner + Vector2i(x, y)
 | 
						|
					remove_tile(position)
 | 
						|
			multi_selecting = false
 | 
						|
 | 
						|
func show_scroll_preview() -> void:
 | 
						|
	$TileCursor/Previews.show()
 | 
						|
	for i in [$"TileCursor/Previews/-2", $"TileCursor/Previews/-1", $"TileCursor/Previews/0", $"TileCursor/Previews/1", $"TileCursor/Previews/2"]:
 | 
						|
		var position = selected_tile_index + int(i.name)
 | 
						|
		var selector = tile_list[wrap(position, 0, tile_list.size())]
 | 
						|
		i.texture = selector.get_node("%Icon").texture
 | 
						|
		i.get_node("Overlay").texture = selector.get_node("%SecondaryIcon").texture
 | 
						|
		i.get_node("Overlay").region_rect = selector.get_node("%SecondaryIcon").region_rect
 | 
						|
		i.region_rect = selector.get_node("%Icon").region_rect
 | 
						|
	$TileCursor/Timer.start()
 | 
						|
	await $TileCursor/Timer.timeout
 | 
						|
	$TileCursor/Previews.hide()
 | 
						|
	
 | 
						|
func open_tile_selection_menu_scene_ref(selector: TilePropertySceneRef) -> void:
 | 
						|
	open_tile_menu()
 | 
						|
	current_state = EditorState.SELECTING_TILE_SCENE
 | 
						|
	selection_filter = selector.editing_node.get_node("EditorPropertyExposer").filters[selector.tile_property_name]
 | 
						|
	for i in get_tree().get_nodes_in_group("Selectors"):
 | 
						|
		i.disabled = !i.has_meta(selection_filter)
 | 
						|
		i.update_visuals()
 | 
						|
	await tile_selected
 | 
						|
	if is_instance_valid(selector) == false:
 | 
						|
		return
 | 
						|
	selector.set_scene(current_entity_selector)
 | 
						|
	close_tile_menu()
 | 
						|
	current_state = EditorState.MODIFYING_TILE
 | 
						|
func on_tile_selected(selector: EditorTileSelector) -> void:
 | 
						|
	mode = selector.type
 | 
						|
	current_entity_selector = selector
 | 
						|
	selected_tile_index = tile_list.find(selector)
 | 
						|
	print(selected_tile_index)
 | 
						|
	if selector.type == 1:
 | 
						|
		current_entity_scene = selector.entity_scene
 | 
						|
		current_spawn_offset = selector.tile_offset
 | 
						|
	elif selector.type == 2:
 | 
						|
		current_terrain_id = selector.terrain_id
 | 
						|
	else:
 | 
						|
		current_tile_source = selector.source_id
 | 
						|
		current_tile_coords = selector.tile_coords
 | 
						|
		current_tile_flip = Vector2(selector.flip_h, selector.flip_v)
 | 
						|
	tile_selected.emit(selector)
 | 
						|
 | 
						|
func reset_values_for_play() -> void:
 | 
						|
	Global.score = 0
 | 
						|
	Global.lives = 0
 | 
						|
	Global.coins = 0
 | 
						|
	cleanup()
 | 
						|
 | 
						|
func place_tile(tile_position := Vector2i.ZERO, use_copy := false) -> void:
 | 
						|
	$TileCursor/Previews.hide()
 | 
						|
	var mode_to_use = mode
 | 
						|
	if use_copy:
 | 
						|
		if copied_node != null:
 | 
						|
			mode_to_use = 1
 | 
						|
		elif copied_tile_terrain_id != -1:
 | 
						|
			mode_to_use = 2
 | 
						|
		else:
 | 
						|
			mode_to_use = 0
 | 
						|
	if mode_to_use == 0:
 | 
						|
		var alt_tile := 0
 | 
						|
		if current_tile_flip.x != 0:
 | 
						|
			alt_tile += TileSetAtlasSource.TRANSFORM_FLIP_H
 | 
						|
		if current_tile_flip.y != 0:
 | 
						|
			alt_tile += TileSetAtlasSource.TRANSFORM_FLIP_V
 | 
						|
		remove_tile(tile_position)
 | 
						|
		check_connect_boundary_tiles(tile_position, current_layer)
 | 
						|
		var source = current_tile_source
 | 
						|
		var atlas = current_tile_coords
 | 
						|
		if use_copy:
 | 
						|
			source = copied_tile_source_id
 | 
						|
			atlas = copied_tile_atlas_coors
 | 
						|
		tile_layer_nodes[current_layer].set_cell(tile_position, source, atlas, alt_tile)
 | 
						|
	elif mode_to_use == 2:
 | 
						|
		var terrain_id = current_terrain_id
 | 
						|
		if use_copy:
 | 
						|
			terrain_id = copied_tile_terrain_id
 | 
						|
		remove_tile(tile_position)
 | 
						|
		check_connect_boundary_tiles(tile_position, current_layer)
 | 
						|
		BetterTerrain.set_cell(tile_layer_nodes[current_layer], tile_position, terrain_id)
 | 
						|
	else:
 | 
						|
		var overlapping_tile = null
 | 
						|
		if entity_tiles[current_layer].get(tile_position) != null and current_entity_scene != null:
 | 
						|
			overlapping_tile = entity_tiles[current_layer][tile_position]
 | 
						|
			if overlapping_tile.scene_file_path == current_entity_scene.resource_path:
 | 
						|
				return
 | 
						|
		remove_tile(tile_position)
 | 
						|
		var node: Node = null
 | 
						|
		if use_copy and copied_node != null:
 | 
						|
			node = copied_node.duplicate()
 | 
						|
			var offset := Vector2i.ZERO
 | 
						|
			var off_string = EntityIDMapper.map[EntityIDMapper.get_map_id(copied_node.scene_file_path)][1].split(",")
 | 
						|
			offset = Vector2i(int(off_string[0]), int(off_string[1]))
 | 
						|
 | 
						|
			node.global_position = (tile_position * 16) + (Vector2i(8, 8) + offset)
 | 
						|
		else:
 | 
						|
			node = current_entity_scene.instantiate()
 | 
						|
			node.global_position = (tile_position * 16) + (Vector2i(8, 8) + current_spawn_offset)
 | 
						|
		node.set_meta("tile_position", tile_position)
 | 
						|
		node.set_meta("tile_offset", current_spawn_offset)
 | 
						|
		entity_layer_nodes[current_layer].add_child(node)
 | 
						|
		node.reset_physics_interpolation()
 | 
						|
		entity_tiles[current_layer].set(tile_position, node)
 | 
						|
	BetterTerrain.update_terrain_cell(tile_layer_nodes[current_layer], tile_position, true)
 | 
						|
 | 
						|
func check_connect_boundary_tiles(tile_position := Vector2i.ZERO, layer := 0) -> void:
 | 
						|
	if tile_position.y > 0:
 | 
						|
		tile_layer_nodes[layer].set_cell(tile_position + Vector2i.DOWN, 6, BOUNDARY_CONNECT_TILE)
 | 
						|
	if tile_position.x <= -16:
 | 
						|
		tile_layer_nodes[layer].set_cell(tile_position + Vector2i.LEFT, 6, BOUNDARY_CONNECT_TILE)
 | 
						|
	if tile_position.y > 0 and tile_position.x <= -16:
 | 
						|
		tile_layer_nodes[layer].set_cell(tile_position + Vector2i.LEFT + Vector2i.DOWN, 6, BOUNDARY_CONNECT_TILE)
 | 
						|
 | 
						|
func remove_tile(tile_position := Vector2i.ZERO) -> void:
 | 
						|
	$TileCursor/Previews.hide()
 | 
						|
	tile_layer_nodes[current_layer].set_cell(tile_position, -1)
 | 
						|
	if entity_tiles[current_layer].get(tile_position) != null:
 | 
						|
		if entity_tiles[current_layer].get(tile_position) is Player:
 | 
						|
			return
 | 
						|
		entity_tiles[current_layer].get(tile_position).queue_free()
 | 
						|
	entity_tiles[current_layer].erase(tile_position)
 | 
						|
	BetterTerrain.update_terrain_cell(tile_layer_nodes[current_layer], tile_position, true)
 | 
						|
 | 
						|
func global_position_to_tile_position(position := Vector2.ZERO) -> Vector2i:
 | 
						|
	return Vector2i(position / 16)
 | 
						|
 | 
						|
func theme_selected(theme_idx := 0) -> void:
 | 
						|
	ResourceSetterNew.cache.clear()
 | 
						|
	AudioManager.current_level_theme = ""
 | 
						|
	$Level.theme = Level.THEME_IDXS[theme_idx]
 | 
						|
	Global.level_theme = $Level.theme
 | 
						|
	Global.level_theme_changed.emit()
 | 
						|
 | 
						|
func time_selected(time_idx := 0) -> void:
 | 
						|
	ResourceSetterNew.cache.clear()
 | 
						|
	AudioManager.current_level_theme = ""
 | 
						|
	$Level.theme_time = ["Day", "Night"][time_idx]
 | 
						|
	Global.theme_time = ["Day", "Night"][time_idx]
 | 
						|
	$Level/LevelBG.time_of_day = time_idx
 | 
						|
	Global.level_theme_changed.emit()
 | 
						|
 | 
						|
func music_selected(music_idx := 0) -> void:
 | 
						|
	bgm_id = music_idx
 | 
						|
 | 
						|
func campaign_selected(campaign_idx := 0) -> void:
 | 
						|
	ResourceSetterNew.cache.clear()
 | 
						|
	Global.current_campaign = ["SMB1", "SMBLL", "SMBS", "SMBANN"][campaign_idx]
 | 
						|
	$Level.campaign = Global.current_campaign
 | 
						|
	Global.level_theme_changed.emit()
 | 
						|
 | 
						|
func backscroll_toggled(new_value := false) -> void:
 | 
						|
	$Level.can_backscroll = new_value
 | 
						|
 | 
						|
func height_limit_changed(new_value := 0) -> void:
 | 
						|
	$Level.vertical_height = -new_value
 | 
						|
 | 
						|
func time_limit_changed(new_value := 0) -> void:
 | 
						|
	$Level.time_limit = new_value
 | 
						|
 | 
						|
func low_gravity_toggled(new_value := false) -> void:
 | 
						|
	Global.entity_gravity = 10 if new_value == false else 5
 | 
						|
	for i: Player in get_tree().get_nodes_in_group("Players"):
 | 
						|
		i.low_gravity = new_value
 | 
						|
 | 
						|
func transition_to_sublevel(sub_lvl_idx := 0) -> void:
 | 
						|
	Global.can_pause = false
 | 
						|
	var play_transition = playing_level
 | 
						|
	if play_transition:
 | 
						|
		await Global.do_fake_transition()
 | 
						|
	else:
 | 
						|
		level_file = $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
 | 
						|
		LevelPersistance.reset_states()
 | 
						|
	sub_level_id = sub_lvl_idx
 | 
						|
	await $LevelLoader.load_level(sub_lvl_idx)
 | 
						|
	if Settings.file.visuals.transition_animation == 0:
 | 
						|
		Global.do_fake_transition(0.1)
 | 
						|
	await get_tree().physics_frame
 | 
						|
	if (play_pipe_transition or play_door_transition) and play_transition:
 | 
						|
		parse_tiles()
 | 
						|
		if play_pipe_transition:
 | 
						|
			get_tree().call_group("Pipes", "run_pipe_check")
 | 
						|
		if play_door_transition:
 | 
						|
			get_tree().call_group("Doors", "run_door_check")
 | 
						|
		update_music()
 | 
						|
	PipeArea.exiting_pipe_id = -1
 | 
						|
	Global.can_pause = true
 | 
						|
 | 
						|
func _input(event: InputEvent) -> void:
 | 
						|
	if event is InputEventJoypadButton or event is InputEventJoypadMotion:
 | 
						|
		%ControllerInputWarning.show()
 | 
						|
	else:
 | 
						|
		%ControllerInputWarning.hide()
 | 
						|
 | 
						|
func get_tile_properties(tile: Node) -> Array:
 | 
						|
	var properties := []
 | 
						|
	var old_properties := []
 | 
						|
	if tile.get_node_or_null("EditorPropertyExposer") == null:
 | 
						|
		return []
 | 
						|
	
 | 
						|
	var property_exposer: PropertyExposer = tile.get_node_or_null("EditorPropertyExposer")
 | 
						|
	old_properties = tile.get_property_list()
 | 
						|
	for i in old_properties:
 | 
						|
		if property_exposer.properties.has(i.name):
 | 
						|
			properties.append(i)
 | 
						|
	return properties
 | 
						|
 | 
						|
 | 
						|
func on_tree_exited() -> void:
 | 
						|
	pass # Replace with function body.
 |