@tool extends Control class_name WaveMaker signal spawnQtyChanged(newQty : int) const TROOP_SCENE = preload("res://addons/LevelEditor/UI/Troop/Troop.tscn") var level : Level var enemies : Dictionary var currentWave : int = -1 @onready var autoLaunchLevel : CheckButton = $VBC/HBC3/AutoLaunchLevel @onready var levelSelect : CustomOptionButton = $VBC/HBC/LevelSelect @onready var spawnQty : CustomLineEdit = $VBC/HBC4/SpawnQty @onready var waveTabContainer : TabContainer = $VBC/ScrollContainer/WaveContainer @onready var towerSelector : ItemList = $VBC/HBC5/TowerSelector func _ready() -> void: resetApp() towerSelector.clear() towerSelector.max_columns = Tower.TYPE.size() for towerType : String in Tower.TYPE: if Tower.TYPE.NONE != Tower.TYPE.get(towerType): towerSelector.add_item(" " + towerType + " ") func _input(event: InputEvent) -> void: if event is not InputEventKey || !event.pressed: return # NOTE prevent to select new wave button if event.keycode == KEY_PAGEUP: waveTabContainer.select_next_available() elif event.keycode == KEY_PAGEDOWN: waveTabContainer.select_previous_available() func buildTree() -> void: if !level: return manageAllowedTowers() autoLaunchLevel.button_pressed = level.auto_start spawnQty.setValue(level.laneCount) for i in level.waves.size(): waveTabContainer.add_child(buildWave(level.waves[i])) recreateTabBar() func manageAllowedTowers() -> void: towerSelector.deselect_all() for towerAllowed in level.allowedTowers: # NOTE minus one is for remove none value towerSelector.select(towerAllowed - 1, false) func buildWave(wave : Wave) -> VBoxContainer: var troopContainer : VBoxContainer = VBoxContainer.new() for i in wave.troops.size(): var troop : Troop = wave.troops[i] if troop.spawn_delay > 0 || i > 0 && \ !troopContainer.get_child(troopContainer.get_child_count() - 1).has_meta("troop_group"): troopContainer.add_child(HSeparator.new()) var nodeToAppend : BoxContainer = troopContainer if i < wave.troops.size() -1 && wave.troops[i + 1].spawn_delay == 0: if i == 0 || !troopContainer.get_child(troopContainer.get_child_count() - 1).has_meta("troop_group"): nodeToAppend = HBoxContainer.new() nodeToAppend.size_flags_horizontal = Control.SIZE_SHRINK_CENTER nodeToAppend.set_meta("troop_group", true) troopContainer.add_child(nodeToAppend) if i > 0 && troop.spawn_delay == 0: nodeToAppend = troopContainer.get_child(troopContainer.get_child_count() - 1) nodeToAppend.add_child(VSeparator.new()) nodeToAppend.add_child(createTroop(troop, wave)) var addTroopBtn : Button = Button.new() addTroopBtn.text = "Ajouter une troupe" addTroopBtn.pressed.connect(addTroop.bind(wave)) troopContainer.add_child(addTroopBtn) return troopContainer func createTroop(troop : Troop, wave : Wave) -> TroopMaker: var enemyContainer : TroopMaker = TROOP_SCENE.instantiate() enemyContainer.setTroop(troop, wave.troops.find(troop)) enemyContainer.troopDeleted.connect(removeTroop.bind(troop, wave)) enemyContainer.troopChanged.connect(refreshWaveNode.bind(wave, level.waves.find(wave))) return enemyContainer func cleanMenu() -> void: for child in waveTabContainer.get_children(): waveTabContainer.remove_child(child) child.queue_free() func addTroop(toWave : Wave) -> void: toWave.troops.append(Troop.new()) refreshWaveNode(toWave, currentWave) func removeTroop(troop : Troop, fromWave : Wave) -> void: fromWave.troops.erase(troop) refreshWaveNode(fromWave, currentWave) func refreshWaveNode(wave : Wave, waveIdx : int) -> void: var waveNode : VBoxContainer = waveTabContainer.get_child(waveIdx) waveTabContainer.remove_child(waveNode) waveNode.queue_free() var waveUI : VBoxContainer = buildWave(wave) waveTabContainer.add_child(waveUI) waveTabContainer.move_child(waveUI, waveIdx) recreateTabBar() waveTabContainer.current_tab = waveIdx func cleanAndBuildMenu() -> void: cleanMenu() buildTree() func resetApp() -> void: enemies = getOptionsFromFile(Helper.RESOURCE_TYPE.ENEMY) levelSelect.setOptions(getOptionsFromFile(Helper.RESOURCE_TYPE.LEVEL)) cleanAndBuildMenu() func removeWave() -> void: level.waves.remove_at(currentWave) var wave : VBoxContainer = waveTabContainer.get_child(currentWave) waveTabContainer.remove_child(wave) wave.queue_free() recreateTabBar() func addWave() -> void: var wave : Wave = Wave.new() level.waves.append(wave) waveTabContainer.add_child(buildWave(wave)) recreateTabBar() waveTabContainer.current_tab = level.waves.size() - 1 func changeWaveOrder(newPos : int) -> void: var newWaveOrder : Array[Wave] var waveToMove = level.waves[currentWave] for i in level.waves.size(): if i == 0 && newPos == 0: newWaveOrder.append(waveToMove) if i != currentWave: newWaveOrder.append(level.waves[i]) if i == newPos && newPos != 0: newWaveOrder.append(waveToMove) currentWave = newPos level.waves = newWaveOrder func selectLevel(levelPath : String) -> void : level = load(levelPath) cleanAndBuildMenu() func tabFocusHaschanged(idx : int) -> void: currentWave = idx func _on_auto_launch_wave_toggled(toggled_on: bool) -> void: level.auto_start = toggled_on ## [color=red][b]DANGER :[/b] NOT READY WITH THE NEW PATH SYSTEM[/color][br] ## If you want to use the level maker create manually a [code].tres[/code] file in Level folder ## and click on the resfresh button func _on_new_level_pressed() -> void: return level = Level.new() var levelName = "level_" + str(levelSelect.item_count + 1) levelSelect.addOption(Helper.LEVEL_DIR + levelName + ".tres", levelName, true) _on_save_pressed() func _on_save_pressed() -> void: ResourceSaver.save(level, levelSelect.selectedValue, ResourceSaver.FLAG_BUNDLE_RESOURCES) func onSelectedTowerChange(index: int, selected: int) -> void: # NOTE Adding one for taking NONE value in account index += 1 if selected: level.allowedTowers.append(index) else: level.allowedTowers.erase(index) func getOptionsFromFile(type: Helper.RESOURCE_TYPE) -> Dictionary : var files : Dictionary var filePaths : Array[String] var pattern : String if type == Helper.RESOURCE_TYPE.LEVEL: filePaths = Helper.getResourcesPaths(type) pattern = Helper.RESOURCE_FILE_PATTERN else: filePaths = Helper.getPackedScenesPaths(type) pattern = Helper.SCENE_FILE_PATTERN var regex : RegEx = RegEx.create_from_string(pattern) for file in filePaths: var fileMatch : RegExMatch = regex.search(file) files.set(fileMatch.strings[1], file) return files func recreateTabBar() -> void: var waveTabBar : TabBar = waveTabContainer.get_tab_bar() for i in waveTabBar.tab_count: if i < waveTabContainer.get_child_count(): waveTabBar.set_tab_title(i, "Vague N°" + str(i + 1)) else: waveTabBar.remove_tab(i) func onSpawnQtyChange(newValue: int) -> void: level.laneCount = newValue spawnQtyChanged.emit(newValue)