class_name BattleScene extends Node3D @export var actionBox:ActionBox = null @export var battleFighterScenes:Node @export var cursorScenes:Node signal neverEmitted func _init() ->void: BATTLE.battleScene = self BATTLE.battleStarted.connect(onBattleStarted) func onBattleStarted() -> void: pass func getBattleDecisions(fighters:Array[BattleFighter]) -> Array[BattleDecision]: var decisions:Array[BattleDecision] = [] while fighters.size() > decisions.size(): var fighter = fighters[decisions.size()] var decision:BattleDecision = null # Simulate walking forward animation like in Final Fantasy await get_tree().create_timer(0.5).timeout # Until decision made... while decision == null: # Get the selected action actionBox.visible = true var action = await self.actionBox.getAction(fighter) # Go back to previous fighter if action == ActionBox.Action.BACK: decisions.pop_back() actionBox.visible = false # Get target for attack elif action == ActionBox.Action.ATTACK: var targets = await _getTargets(fighter, fighter.movePrimary) decision = BattleDecision.new( fighter.movePrimary, fighter, targets ) # Get Magic move and targets elif action == ActionBox.Action.MAGIC: var magicMove = await _getMagicMove(fighter) if magicMove != null: var targets = await _getTargets(fighter, magicMove) decision = BattleDecision.new( magicMove, fighter, targets ) # Get Item use and targets elif action == ActionBox.Action.ITEM: var itemMove = await _getItemUse(fighter) if itemMove != null: var targets = await _getTargets(fighter, itemMove) decision = BattleDecision.new( itemMove, fighter, targets ) if decision != null: decisions.append(decision) # Return the made decision return decisions func _getInitialTargetPosition( fighter:BattleFighter, move:BattleAction, possiblePositions:Array[BattleSingleton.BattlePosition], ) -> BattleSingleton.BattlePosition: # Find ally in possible positions if move.preferAlly: for pos in possiblePositions: var targetFighter = BATTLE.getFighterAtPosition(pos) if targetFighter != null and targetFighter.team == fighter.team: return pos # Otherwise, prefer to target enemy for pos in possiblePositions: var targetFighter = BATTLE.getFighterAtPosition(pos) if targetFighter != null and targetFighter.team != fighter.team: return pos # If still noting found, just return first possible position if possiblePositions.size() > 0: return possiblePositions[0] # Fallback (should not happen) assert(false) return BATTLE.BattlePosition.LEFT_TOP_BACK func _getTargets(fighter:BattleFighter, move:BattleAction) -> Array[BattleFighter]: assert(fighter != null) assert(move != null) # Determine possible targets and whether to blink or not var possiblePositions:Array[BattleSingleton.BattlePosition] = [] if move.canTargetEnemy: possiblePositions.append_array(BATTLE.getEnemyPositions()) if move.canTargetAlly: possiblePositions.append_array(BATTLE.getAllyPositions()) # Should not be possible to have no possible targets here assert(possiblePositions.size() > 0) var activePositions:Array[BattleSingleton.BattlePosition] = [ _getInitialTargetPosition(fighter, move, possiblePositions) ] # This is where output will be stored. var selectedPositions:Array[BattleSingleton.BattlePosition] = [] # Here we wait for a selection to be confirmed. while selectedPositions.size() == 0: var blink = activePositions.size() > 1 # Show cursors for cursor in cursorScenes.get_children(): if !(cursor is BattleCursorIcon): continue if cursor.battlePosition in activePositions: if blink: cursor.mode = BattleCursorIcon.Mode.BLINKING else: cursor.mode = BattleCursorIcon.Mode.ACTIVE else: cursor.mode = BattleCursorIcon.Mode.INACTIVE # TODO: Allow movement here, wait for selection, etc. # Wait 1 second for now and select all possible targets await get_tree().create_timer(1.0).timeout # selectedPositions = possiblePositions # By this point selection has been made, hide all cursors for cursor in cursorScenes.get_children(): if !(cursor is BattleCursorIcon): continue cursor.mode = BattleCursorIcon.Mode.INACTIVE # Convert selected positions to fighters var targets:Array[BattleFighter] = [] for pos in selectedPositions: var targetFighter = BATTLE.getFighterAtPosition(pos) if targetFighter != null: targets.append(targetFighter) # Should not be possible to have no targets here assert(targets.size() > 0) return targets func _getMagicMove(fighter:BattleFighter) -> BattleAction: return null func _getItemUse(fighter:BattleFighter) -> BattleAction: return null func getFighterSceneAtPosition(pos:BattleSingleton.BattlePosition) -> BattleFighterScene: for fighterScene in battleFighterScenes.get_children(): if !(fighterScene is BattleFighterScene): continue if fighterScene.battlePosition == pos: return fighterScene return null func getBattleCursorAtPosition(pos:BattleSingleton.BattlePosition) -> BattleCursorIcon: for cursorScene in cursorScenes.get_children(): if !(cursorScene is BattleCursorIcon): continue if cursorScene.battlePosition == pos: return cursorScene return null