LevelEditor.gd 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. class_name LevelEditor
  2. extends Node
  3. const CAM_MOVE_SPEED_SLOW := 128
  4. const CAM_MOVE_SPEED_FAST := 256
  5. var cursor_tile_position := Vector2i.ZERO
  6. const CURSOR_OFFSET := Vector2(-8, -8)
  7. var mode := 0
  8. var current_entity_selector: EditorTileSelector = null
  9. var current_entity_scene: PackedScene = null
  10. var current_spawn_offset := Vector2i.ZERO
  11. var current_tile_source := 0
  12. var current_tile_coords := Vector2i.ZERO
  13. var current_tile_flip := Vector2.ZERO ## 1 = true, 0 = false, x = hori, y = vert
  14. var menu_open := false
  15. var testing_level := false
  16. var entity_tiles := [{}, {}, {}, {}, {}]
  17. static var playing_level := false
  18. var tile_list: Array[EditorTileSelector] = []
  19. var tile_offsets := {}
  20. signal level_start
  21. var selected_tile_index := 0
  22. var can_move_cam := true
  23. 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"]
  24. 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"]
  25. var bgm_id := 0
  26. const MUSIC_TRACK_DIR := "res://Assets/Audio/BGM/"
  27. var select_start := Vector2i.ZERO
  28. var select_end := Vector2i.ZERO
  29. signal close_confirm(save: bool)
  30. var sub_level_id := 0
  31. const BLANK_FILE := {"Info": {}, "Levels": [{}, {}, {}, {}, {}]}
  32. static var level_file = {"Info": {}, "Levels": [{}, {}, {}, {}, {}]}
  33. var current_layer := 0
  34. @onready var tile_layer_nodes: Array[TileMapLayer] = [%TileLayer1, %TileLayer2, %TileLayer3, %TileLayer4, %TileLayer5]
  35. @onready var entity_layer_nodes := [%EntityLayer1, %EntityLayer2, %EntityLayer3, %EntityLayer4, %EntityLayer5]
  36. var saved_entity_layers := [null, null, null, null, null]
  37. var copied_node: Node = null
  38. var copied_tile_offset := Vector2.ZERO
  39. var copied_tile_source_id := -1
  40. var copied_tile_atlas_coors := Vector2i.ZERO
  41. var copied_tile_terrain_id := -1
  42. const CURSOR_ERASOR := preload("uid://d0j1my4kuapgb")
  43. const CURSOR_PEN = preload("uid://bt0brcjv0efmw")
  44. const CURSOR_PENCIL = preload("uid://c8oyhfvlv2gvh")
  45. const CURSOR_RULER = preload("uid://cg2wkxnmjgplf")
  46. const CURSOR_INSPECT = preload("uid://1l3foyjqeej")
  47. var multi_selecting := false
  48. var inspect_mode := false
  49. var inspect_menu_open := false
  50. var current_inspect_tile: Node = null
  51. var selection_filter := ""
  52. static var level_author := ""
  53. static var level_desc := ""
  54. static var level_name := ""
  55. static var difficulty := 0
  56. var current_terrain_id := 0
  57. static var load_play := false
  58. signal tile_selected(tile_selector: EditorTileSelector)
  59. var tile_menu_open := false
  60. signal editor_start
  61. enum EditorState{IDLE, TILE_MENU, MODIFYING_TILE, SAVE_MENU, SELECTING_TILE_SCENE, QUITTING, PLAYTESTING, TRACK_EDITING}
  62. var current_state := EditorState.IDLE
  63. static var play_pipe_transition := false
  64. static var play_door_transition := false
  65. const BOUNDARY_CONNECT_TILE := Vector2i.ZERO
  66. var undo_redo = UndoRedo.new()
  67. func _ready() -> void:
  68. $TileMenu.hide()
  69. Global.set_discord_status("In The Level Editor...")
  70. Global.level_editor = self
  71. playing_level = false
  72. menu_open = $TileMenu.visible
  73. Global.get_node("GameHUD").hide()
  74. Global.can_time_tick = false
  75. for i in get_tree().get_nodes_in_group("Selectors"):
  76. tile_list.append(i)
  77. var idx := 0
  78. for i in music_track_list:
  79. if i == "": continue
  80. $%LevelMusic.add_item(tr(music_track_names[idx]).to_upper())
  81. idx += 1
  82. await get_tree().process_frame
  83. Level.start_level_path = scene_file_path
  84. var layer_idx := 0
  85. for i in entity_layer_nodes:
  86. for x in i.get_children():
  87. entity_tiles[layer_idx][x.get_meta("tile_position")] = x
  88. if level_file != {}:
  89. Level.can_set_time = true
  90. $LevelLoader.load_level(Checkpoint.sublevel_id)
  91. if Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
  92. $Info.hide()
  93. %Grid.hide()
  94. play_level()
  95. else:
  96. Global.current_game_mode = Global.GameMode.LEVEL_EDITOR
  97. else:
  98. Global.current_game_mode = Global.GameMode.LEVEL_EDITOR
  99. for i: Player in get_tree().get_nodes_in_group("Players"):
  100. i.recenter_camera()
  101. %LevelName.text = level_name
  102. %LevelAuthor.text = level_author
  103. %Description.text = level_desc
  104. func _physics_process(delta: float) -> void:
  105. if current_state == EditorState.IDLE:
  106. handle_tile_cursor()
  107. if [EditorState.IDLE, EditorState.TRACK_EDITING].has(current_state):
  108. handle_camera(delta)
  109. %ThemeName.text = Global.level_theme
  110. handle_hud()
  111. if Input.is_action_just_pressed("editor_open_menu"):
  112. if current_state == EditorState.IDLE:
  113. open_tile_menu()
  114. elif current_state == EditorState.TILE_MENU:
  115. close_tile_menu()
  116. 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:
  117. Checkpoint.passed = false
  118. if current_state == EditorState.PLAYTESTING:
  119. stop_testing()
  120. else:
  121. play_level()
  122. handle_layers()
  123. func handle_hud() -> void:
  124. $TileCursor.visible = current_state == EditorState.IDLE
  125. $Info.visible = not playing_level
  126. %Grid.visible = not playing_level
  127. func quit_editor() -> void:
  128. %QuitDialog.show()
  129. signal level_saved
  130. func open_tile_menu() -> void:
  131. $TileMenu.visible = true
  132. current_state = EditorState.TILE_MENU
  133. for i in get_tree().get_nodes_in_group("Selectors"):
  134. i.disabled = false
  135. i.update_visuals()
  136. func close_tile_menu() -> void:
  137. $TileMenu.visible = false
  138. current_state = EditorState.IDLE
  139. for i in get_tree().get_nodes_in_group("Selectors"):
  140. i.disabled = false
  141. func save_level_before_exit() -> void:
  142. tile_menu_open = true
  143. open_save_dialog()
  144. await level_saved
  145. go_back_to_menu()
  146. func copy_node(tile_position := Vector2i.ZERO) -> void:
  147. if tile_layer_nodes[current_layer].get_used_cells().has(tile_position):
  148. var terrain_id = BetterTerrain.get_cell(tile_layer_nodes[current_layer], tile_position)
  149. if terrain_id != -2:
  150. copied_tile_terrain_id = terrain_id
  151. return
  152. mode = 0
  153. copied_tile_source_id = tile_layer_nodes[current_layer].get_cell_source_id(tile_position)
  154. copied_tile_atlas_coors = tile_layer_nodes[current_layer].get_cell_atlas_coords(tile_position)
  155. elif entity_tiles[current_layer].has(tile_position):
  156. copied_node = entity_tiles[current_layer][tile_position].duplicate()
  157. copied_tile_offset = entity_tiles[current_layer][tile_position].get_meta("tile_offset")
  158. func cut_node(tile_position := Vector2i.ZERO) -> void:
  159. var old_copy = copied_node
  160. copy_node(tile_position)
  161. if copied_node != old_copy:
  162. remove_tile(tile_position)
  163. func paste_node(tile_position := Vector2i.ZERO) -> void:
  164. place_tile(tile_position, true)
  165. func go_back_to_menu() -> void:
  166. Global.transition_to_scene("res://Scenes/Levels/CustomLevelMenu.tscn")
  167. func open_bindings_menu() -> void:
  168. $TileMenu/EditorKeybindsView.open()
  169. current_state = EditorState.SAVE_MENU
  170. await $TileMenu/EditorKeybindsView.closed
  171. current_state = EditorState.TILE_MENU
  172. func open_save_dialog() -> void:
  173. current_state = EditorState.SAVE_MENU
  174. can_move_cam = false
  175. %SaveLevelDialog.show()
  176. menu_open = true
  177. func stop_testing() -> void:
  178. cleanup()
  179. return_to_editor()
  180. func cleanup() -> void:
  181. get_tree().paused = false
  182. Global.p_switch_timer = 0
  183. Global.cancel_score_tally()
  184. playing_level = !playing_level
  185. play_pipe_transition = false
  186. play_door_transition = false
  187. Door.unlocked_doors = []
  188. LevelPersistance.reset_states()
  189. KeyItem.total_collected = 0
  190. Global.get_node("GameHUD").visible = playing_level
  191. Global.p_switch_active = false
  192. if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
  193. Global.time = $Level.time_limit
  194. elif Level.can_set_time and playing_level:
  195. Global.time = $Level.time_limit
  196. Global.can_time_tick = playing_level
  197. print(Global.can_time_tick)
  198. func update_music() -> void:
  199. if music_track_list[bgm_id] != "":
  200. $Level.music = load(music_track_list[bgm_id].replace(".remap", ""))
  201. else:
  202. $Level.music = null
  203. func play_level() -> void:
  204. $TileMenu.hide()
  205. menu_open = false
  206. update_music()
  207. reset_values_for_play()
  208. %Camera.enabled = false
  209. level_start.emit()
  210. get_tree().call_group("Players", "editor_level_start")
  211. parse_tiles()
  212. if Global.current_game_mode != Global.GameMode.CUSTOM_LEVEL:
  213. level_file = await $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
  214. current_state = EditorState.PLAYTESTING
  215. handle_hud()
  216. func parse_tiles() -> void:
  217. saved_entity_layers = [null, null, null, null, null]
  218. var idx := 0
  219. for i in entity_layer_nodes:
  220. if is_instance_valid(i) == false:
  221. continue
  222. saved_entity_layers[idx] = i.duplicate(DUPLICATE_USE_INSTANTIATION)
  223. if i is Player:
  224. i.direction = 1
  225. i.velocity = Vector2.ZERO
  226. i.global_position = i.global_position.snapped(Vector2(8, 8))
  227. i.ready.emit()
  228. i.set_process_mode(Node.PROCESS_MODE_INHERIT)
  229. idx += 1
  230. func return_to_editor() -> void:
  231. AudioManager.stop_all_music()
  232. $Level.music = null
  233. %Camera.global_position = get_viewport().get_camera_2d().get_screen_center_position()
  234. %Camera.reset_physics_interpolation()
  235. return_editor_tiles()
  236. %Camera.enabled = true
  237. %Camera.make_current()
  238. editor_start.emit()
  239. current_state = EditorState.IDLE
  240. handle_hud()
  241. func return_editor_tiles() -> void:
  242. for i in entity_layer_nodes:
  243. i.queue_free()
  244. var idx := 0
  245. for i in entity_tiles:
  246. i.clear()
  247. $Level.add_child(saved_entity_layers[idx])
  248. entity_layer_nodes[idx] = saved_entity_layers[idx]
  249. idx += 1
  250. var layer_idx = 0
  251. for x in entity_layer_nodes:
  252. x.process_mode = PROCESS_MODE_DISABLED
  253. for i in x.get_children():
  254. i.owner = self
  255. var _tile_position = (Vector2i(i.global_position) - Vector2i(8, 8)) / 16
  256. entity_tiles[layer_idx].set(i.get_meta("tile_position", Vector2i.ZERO), i)
  257. layer_idx += 1
  258. func handle_camera(delta: float) -> void:
  259. var input_vector = Input.get_vector("editor_cam_left", "editor_cam_right", "editor_cam_up", "editor_cam_down")
  260. %Camera.global_position += input_vector * (CAM_MOVE_SPEED_FAST if Input.is_action_pressed("editor_cam_fast") else CAM_MOVE_SPEED_SLOW) * delta
  261. %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))
  262. %Camera.global_position.x = clamp(%Camera.global_position.x, -256 + (get_viewport().get_visible_rect().size.x / 2), INF)
  263. func handle_layers() -> void:
  264. if Input.is_action_just_pressed("layer_up"):
  265. current_layer += 1
  266. if Input.is_action_just_pressed("layer_down"):
  267. current_layer -= 1
  268. current_layer = clamp(current_layer, 0, entity_layer_nodes.size() - 1)
  269. var idx := 0
  270. for i in entity_layer_nodes:
  271. i.z_index = 0 if current_layer == idx or playing_level else -1
  272. i.modulate = Color(1, 1, 1, 1) if current_layer == idx or playing_level else Color(1, 1, 1, 0.5)
  273. tile_layer_nodes[idx].modulate = i.modulate
  274. tile_layer_nodes[idx].z_index = i.z_index - 1
  275. %LayerDisplay.get_child(idx).modulate = Color.WHITE if current_layer == idx else Color(0.1, 0.1, 0.1, 0.5)
  276. idx += 1
  277. %LayerLabel.text = "Layer " + str(current_layer + 1)
  278. func save_level() -> void:
  279. level_author = %LevelAuthor.text
  280. level_desc = %Description.text
  281. level_name = %LevelName.text
  282. difficulty = %DifficultySlider.value
  283. var file_name = level_name.to_pascal_case() + ".lvl"
  284. %SaveLevelDialog.hide()
  285. menu_open = false
  286. level_file = $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
  287. $LevelSaver.write_file(level_file, file_name)
  288. %SaveDialog.text = str("'") + file_name + "'" + " Saved."
  289. %SaveAnimation.play("Show")
  290. level_saved.emit()
  291. func close_save_menu() -> void:
  292. can_move_cam = true
  293. %SaveLevelDialog.hide()
  294. menu_open = false
  295. current_state = EditorState.TILE_MENU
  296. const CUSTOM_LEVEL_DIR := "user://custom_levels/"
  297. func handle_tile_cursor() -> void:
  298. Input.set_custom_mouse_cursor(null)
  299. var snapped_position = ((%TileCursor.get_global_mouse_position() - CURSOR_OFFSET).snapped(Vector2(16, 16))) + CURSOR_OFFSET
  300. %TileCursor.global_position = (snapped_position)
  301. var old_index := selected_tile_index
  302. var tile_position = global_position_to_tile_position(snapped_position + Vector2(-8, -8))
  303. tile_position.y = clamp(tile_position.y, -30, 1)
  304. tile_position.x = clamp(tile_position.x, -16, INF)
  305. cursor_tile_position = tile_position
  306. inspect_mode = Input.is_action_pressed("editor_inspect") and not multi_selecting
  307. if inspect_mode and current_state == EditorState.IDLE:
  308. handle_inspection(tile_position)
  309. return
  310. if Input.is_action_pressed("mb_left"):
  311. if Input.is_action_pressed("editor_select") and not multi_selecting:
  312. multi_select_start(tile_position)
  313. elif Input.is_action_pressed("editor_select") == false:
  314. multi_selecting = false
  315. place_tile(tile_position)
  316. Input.set_custom_mouse_cursor(CURSOR_PENCIL)
  317. if Input.is_action_pressed("mb_right"):
  318. if Input.is_action_pressed("editor_select") and not multi_selecting:
  319. multi_select_start(tile_position)
  320. Input.set_custom_mouse_cursor(CURSOR_RULER)
  321. elif Input.is_action_pressed("editor_select") == false:
  322. multi_selecting = false
  323. remove_tile(tile_position)
  324. Input.set_custom_mouse_cursor(CURSOR_ERASOR)
  325. if current_state == EditorState.IDLE:
  326. if Input.is_action_just_pressed("scroll_up"):
  327. selected_tile_index += 1
  328. if Input.is_action_just_pressed("scroll_down"):
  329. selected_tile_index -= 1
  330. if Input.is_action_just_pressed("editor_copy"):
  331. copy_node(tile_position)
  332. elif Input.is_action_just_pressed("editor_cut"):
  333. cut_node(tile_position)
  334. elif Input.is_action_pressed("ui_paste"):
  335. paste_node(tile_position)
  336. if Input.is_action_just_pressed("pick_tile"):
  337. pick_tile(tile_position)
  338. handle_multi_selecting(tile_position)
  339. if old_index != selected_tile_index:
  340. selected_tile_index = wrap(selected_tile_index, 0, tile_list.size())
  341. on_tile_selected(tile_list[selected_tile_index])
  342. show_scroll_preview()
  343. func pick_tile(tile_position := Vector2i.ZERO) -> void:
  344. if tile_layer_nodes[current_layer].get_used_cells().has(tile_position):
  345. var terrain_id = BetterTerrain.get_cell(tile_layer_nodes[current_layer], tile_position)
  346. if terrain_id != -2:
  347. mode = 2
  348. current_terrain_id = terrain_id
  349. return
  350. mode = 0
  351. current_tile_source = tile_layer_nodes[current_layer].get_cell_source_id(tile_position)
  352. current_tile_coords = tile_layer_nodes[current_layer].get_cell_atlas_coords(tile_position)
  353. elif entity_tiles[current_layer].has(tile_position):
  354. mode = 1
  355. current_entity_scene = load(entity_tiles[current_layer][tile_position].scene_file_path)
  356. current_spawn_offset = entity_tiles[current_layer][tile_position].get_meta("tile_offset")
  357. func handle_inspection(tile_position := Vector2i.ZERO) -> void:
  358. Input.set_custom_mouse_cursor(CURSOR_INSPECT)
  359. if Input.is_action_just_pressed("mb_left"):
  360. if entity_tiles[current_layer].get(tile_position) != null:
  361. open_tile_properties(entity_tiles[current_layer][tile_position])
  362. func open_tile_properties(tile: Node2D) -> void:
  363. var properties = get_tile_properties(tile)
  364. if properties.is_empty():
  365. return
  366. current_inspect_tile = tile
  367. %TileModifierMenu.override_scenes = tile.get_node("EditorPropertyExposer").properties_force_selector
  368. %TileModifierMenu.properties = properties
  369. %TileModifierMenu.editing_node = current_inspect_tile
  370. %TileModifierMenu.open()
  371. current_state = EditorState.MODIFYING_TILE
  372. %TileModifierMenu.position = tile.get_global_transform_with_canvas().origin
  373. %TileModifierMenu.position.x = clamp(%TileModifierMenu.position.x, 0, get_viewport().get_visible_rect().size.x - %TileModifierMenu.size.x - 2)
  374. %TileModifierMenu.position.y = clamp(%TileModifierMenu.position.y, 0, get_viewport().get_visible_rect().size.y - %TileModifierMenu.size.y - 2)
  375. await %TileModifierMenu.closed
  376. current_state = EditorState.IDLE
  377. func multi_select_start(tile_position := Vector2i.ZERO) -> void:
  378. select_start = tile_position
  379. multi_selecting = true
  380. func handle_multi_selecting(tile_position := Vector2i.ZERO) -> void:
  381. select_end = tile_position
  382. %MultiSelectRect.visible = multi_selecting
  383. var top_corner := select_start
  384. if select_start.x > select_end.x:
  385. top_corner.x = select_end.x
  386. if select_start.y > select_end.y:
  387. top_corner.y = select_end.y
  388. %MultiSelectRect.global_position = top_corner * 16
  389. %MultiSelectRect.size = abs(select_end - select_start) * 16 + Vector2i(16, 16)
  390. if multi_selecting:
  391. Input.set_custom_mouse_cursor(CURSOR_RULER)
  392. if Input.is_action_just_released("mb_left"):
  393. for x in abs(select_end.x - select_start.x) + 1:
  394. for y in abs(select_end.y - select_start.y) + 1:
  395. var position = top_corner + Vector2i(x, y)
  396. place_tile(position)
  397. multi_selecting = false
  398. if Input.is_action_just_released("mb_right"):
  399. for x in abs(select_end.x - select_start.x) + 1:
  400. for y in abs(select_end.y - select_start.y) + 1:
  401. var position = top_corner + Vector2i(x, y)
  402. remove_tile(position)
  403. multi_selecting = false
  404. func show_scroll_preview() -> void:
  405. $TileCursor/Previews.show()
  406. for i in [$"TileCursor/Previews/-2", $"TileCursor/Previews/-1", $"TileCursor/Previews/0", $"TileCursor/Previews/1", $"TileCursor/Previews/2"]:
  407. var position = selected_tile_index + int(i.name)
  408. var selector = tile_list[wrap(position, 0, tile_list.size())]
  409. i.texture = selector.get_node("%Icon").texture
  410. i.get_node("Overlay").texture = selector.get_node("%SecondaryIcon").texture
  411. i.get_node("Overlay").region_rect = selector.get_node("%SecondaryIcon").region_rect
  412. i.region_rect = selector.get_node("%Icon").region_rect
  413. $TileCursor/Timer.start()
  414. await $TileCursor/Timer.timeout
  415. $TileCursor/Previews.hide()
  416. func open_tile_selection_menu_scene_ref(selector: TilePropertySceneRef) -> void:
  417. open_tile_menu()
  418. current_state = EditorState.SELECTING_TILE_SCENE
  419. selection_filter = selector.editing_node.get_node("EditorPropertyExposer").filters[selector.tile_property_name]
  420. for i in get_tree().get_nodes_in_group("Selectors"):
  421. i.disabled = !i.has_meta(selection_filter)
  422. i.update_visuals()
  423. await tile_selected
  424. if is_instance_valid(selector) == false:
  425. return
  426. selector.set_scene(current_entity_selector)
  427. close_tile_menu()
  428. current_state = EditorState.MODIFYING_TILE
  429. func on_tile_selected(selector: EditorTileSelector) -> void:
  430. mode = selector.type
  431. current_entity_selector = selector
  432. selected_tile_index = tile_list.find(selector)
  433. print(selected_tile_index)
  434. if selector.type == 1:
  435. current_entity_scene = selector.entity_scene
  436. current_spawn_offset = selector.tile_offset
  437. elif selector.type == 2:
  438. current_terrain_id = selector.terrain_id
  439. else:
  440. current_tile_source = selector.source_id
  441. current_tile_coords = selector.tile_coords
  442. current_tile_flip = Vector2(selector.flip_h, selector.flip_v)
  443. tile_selected.emit(selector)
  444. func reset_values_for_play() -> void:
  445. Global.score = 0
  446. Global.lives = 0
  447. Global.coins = 0
  448. cleanup()
  449. func place_tile(tile_position := Vector2i.ZERO, use_copy := false) -> void:
  450. $TileCursor/Previews.hide()
  451. var mode_to_use = mode
  452. if use_copy:
  453. if copied_node != null:
  454. mode_to_use = 1
  455. elif copied_tile_terrain_id != -1:
  456. mode_to_use = 2
  457. else:
  458. mode_to_use = 0
  459. if mode_to_use == 0:
  460. var alt_tile := 0
  461. if current_tile_flip.x != 0:
  462. alt_tile += TileSetAtlasSource.TRANSFORM_FLIP_H
  463. if current_tile_flip.y != 0:
  464. alt_tile += TileSetAtlasSource.TRANSFORM_FLIP_V
  465. remove_tile(tile_position)
  466. check_connect_boundary_tiles(tile_position, current_layer)
  467. var source = current_tile_source
  468. var atlas = current_tile_coords
  469. if use_copy:
  470. source = copied_tile_source_id
  471. atlas = copied_tile_atlas_coors
  472. tile_layer_nodes[current_layer].set_cell(tile_position, source, atlas, alt_tile)
  473. elif mode_to_use == 2:
  474. var terrain_id = current_terrain_id
  475. if use_copy:
  476. terrain_id = copied_tile_terrain_id
  477. remove_tile(tile_position)
  478. check_connect_boundary_tiles(tile_position, current_layer)
  479. BetterTerrain.set_cell(tile_layer_nodes[current_layer], tile_position, terrain_id)
  480. else:
  481. var overlapping_tile = null
  482. if entity_tiles[current_layer].get(tile_position) != null and current_entity_scene != null:
  483. overlapping_tile = entity_tiles[current_layer][tile_position]
  484. if overlapping_tile.scene_file_path == current_entity_scene.resource_path:
  485. return
  486. remove_tile(tile_position)
  487. var node: Node = null
  488. if use_copy and copied_node != null:
  489. node = copied_node.duplicate()
  490. var offset := Vector2i.ZERO
  491. var off_string = EntityIDMapper.map[EntityIDMapper.get_map_id(copied_node.scene_file_path)][1].split(",")
  492. offset = Vector2i(int(off_string[0]), int(off_string[1]))
  493. node.global_position = (tile_position * 16) + (Vector2i(8, 8) + offset)
  494. else:
  495. node = current_entity_scene.instantiate()
  496. node.global_position = (tile_position * 16) + (Vector2i(8, 8) + current_spawn_offset)
  497. node.set_meta("tile_position", tile_position)
  498. node.set_meta("tile_offset", current_spawn_offset)
  499. entity_layer_nodes[current_layer].add_child(node)
  500. node.reset_physics_interpolation()
  501. entity_tiles[current_layer].set(tile_position, node)
  502. BetterTerrain.update_terrain_cell(tile_layer_nodes[current_layer], tile_position, true)
  503. func check_connect_boundary_tiles(tile_position := Vector2i.ZERO, layer := 0) -> void:
  504. if tile_position.y > 0:
  505. tile_layer_nodes[layer].set_cell(tile_position + Vector2i.DOWN, 6, BOUNDARY_CONNECT_TILE)
  506. if tile_position.x <= -16:
  507. tile_layer_nodes[layer].set_cell(tile_position + Vector2i.LEFT, 6, BOUNDARY_CONNECT_TILE)
  508. if tile_position.y > 0 and tile_position.x <= -16:
  509. tile_layer_nodes[layer].set_cell(tile_position + Vector2i.LEFT + Vector2i.DOWN, 6, BOUNDARY_CONNECT_TILE)
  510. func remove_tile(tile_position := Vector2i.ZERO) -> void:
  511. $TileCursor/Previews.hide()
  512. tile_layer_nodes[current_layer].set_cell(tile_position, -1)
  513. if entity_tiles[current_layer].get(tile_position) != null:
  514. if entity_tiles[current_layer].get(tile_position) is Player:
  515. return
  516. entity_tiles[current_layer].get(tile_position).queue_free()
  517. entity_tiles[current_layer].erase(tile_position)
  518. BetterTerrain.update_terrain_cell(tile_layer_nodes[current_layer], tile_position, true)
  519. func global_position_to_tile_position(position := Vector2.ZERO) -> Vector2i:
  520. return Vector2i(position / 16)
  521. func theme_selected(theme_idx := 0) -> void:
  522. ResourceSetterNew.cache.clear()
  523. AudioManager.current_level_theme = ""
  524. $Level.theme = Level.THEME_IDXS[theme_idx]
  525. Global.level_theme = $Level.theme
  526. Global.level_theme_changed.emit()
  527. func time_selected(time_idx := 0) -> void:
  528. ResourceSetterNew.cache.clear()
  529. AudioManager.current_level_theme = ""
  530. $Level.theme_time = ["Day", "Night"][time_idx]
  531. Global.theme_time = ["Day", "Night"][time_idx]
  532. $Level/LevelBG.time_of_day = time_idx
  533. Global.level_theme_changed.emit()
  534. func music_selected(music_idx := 0) -> void:
  535. bgm_id = music_idx
  536. func campaign_selected(campaign_idx := 0) -> void:
  537. ResourceSetterNew.cache.clear()
  538. Global.current_campaign = ["SMB1", "SMBLL", "SMBS", "SMBANN"][campaign_idx]
  539. $Level.campaign = Global.current_campaign
  540. Global.level_theme_changed.emit()
  541. func backscroll_toggled(new_value := false) -> void:
  542. $Level.can_backscroll = new_value
  543. func height_limit_changed(new_value := 0) -> void:
  544. $Level.vertical_height = -new_value
  545. func time_limit_changed(new_value := 0) -> void:
  546. $Level.time_limit = new_value
  547. func low_gravity_toggled(new_value := false) -> void:
  548. Global.entity_gravity = 10 if new_value == false else 5
  549. for i: Player in get_tree().get_nodes_in_group("Players"):
  550. i.low_gravity = new_value
  551. func transition_to_sublevel(sub_lvl_idx := 0) -> void:
  552. Global.can_pause = false
  553. var play_transition = playing_level
  554. if play_transition:
  555. await Global.do_fake_transition()
  556. else:
  557. level_file = $LevelSaver.save_level(level_name, level_author, level_desc, difficulty)
  558. LevelPersistance.reset_states()
  559. sub_level_id = sub_lvl_idx
  560. $LevelLoader.load_level(sub_lvl_idx)
  561. await get_tree().physics_frame
  562. if (play_pipe_transition or play_door_transition) and play_transition:
  563. parse_tiles()
  564. if play_pipe_transition:
  565. get_tree().call_group("Pipes", "run_pipe_check")
  566. if play_door_transition:
  567. get_tree().call_group("Doors", "run_door_check")
  568. update_music()
  569. PipeArea.exiting_pipe_id = -1
  570. Global.can_pause = true
  571. func _input(event: InputEvent) -> void:
  572. if event is InputEventJoypadButton or event is InputEventJoypadMotion:
  573. %ControllerInputWarning.show()
  574. else:
  575. %ControllerInputWarning.hide()
  576. func get_tile_properties(tile: Node) -> Array:
  577. var properties := []
  578. var old_properties := []
  579. if tile.get_node_or_null("EditorPropertyExposer") == null:
  580. return []
  581. var property_exposer: PropertyExposer = tile.get_node_or_null("EditorPropertyExposer")
  582. old_properties = tile.get_property_list()
  583. for i in old_properties:
  584. if property_exposer.properties.has(i.name):
  585. properties.append(i)
  586. return properties
  587. func on_tree_exited() -> void:
  588. pass # Replace with function body.