class_name BattleCutsceneAction const _NARRATION_BASE:String = "res://dialogue/battle/narration" # State object passed as extra_game_states so {{variable}} tokens resolve in the dialogue file. class BattleNarrationState: var fighter_name:String var user_name:String var target_name:String var move_name:String var damage:int func _init(params:Dictionary) -> void: fighter_name = params.get('fighter_name', '') user_name = params.get('user_name', '') target_name = params.get('target_name', '') move_name = params.get('move_name', '') damage = params.get('damage', 0) # Narrates and executes a single fighter's decision. static func battleDecisionCallable(params:Dictionary) -> int: var decision:BattleDecision = params['decision'] var state = BattleNarrationState.new({ 'user_name': decision.user.name if decision.user is PartyMember else 'Enemy', 'move_name': decision.action.handle, 'target_name': decision.targets[0].name if decision.targets[0] is PartyMember else 'Enemy', }) var cutscene:Cutscene = params['cutscene'] cutscene.addCallable( DialogueAction.getDialogueCallable(_NARRATION_BASE, 'move_perform', [state], DialogueAction.DialogueMode.NARRATION).merged( {'position': Cutscene.CUTSCENE_ADD_NEXT}, false ) ) decision.action.perform({'user': decision.user, 'targets': decision.targets}) return Cutscene.CUTSCENE_CONTINUE static func getBattleDecisionCallable(decision:BattleDecision) -> Dictionary: return { 'function': battleDecisionCallable, 'decision': decision, } static func playerDecisionCallable(params:Dictionary) -> int: # Check end conditions var allPlayersDead:bool = true var allEnemiesDead:bool = true for fighter:BattleFighter in BATTLE.fighterMap.values(): if fighter == null: continue if fighter.status == BattleFighter.Status.DEAD: continue if fighter.isPlayerControlled(): allPlayersDead = false else: allEnemiesDead = false if allPlayersDead: params['cutscene'].addCallable( DialogueAction.getDialogueCallable(_NARRATION_BASE, 'battle_defeat', [], DialogueAction.DialogueMode.NARRATION).merged( {'position': Cutscene.CUTSCENE_ADD_NEXT}, false ) ) return Cutscene.CUTSCENE_END if allEnemiesDead: params['cutscene'].addCallable( DialogueAction.getDialogueCallable(_NARRATION_BASE, 'battle_victory', [], DialogueAction.DialogueMode.NARRATION).merged( {'position': Cutscene.CUTSCENE_ADD_NEXT}, false ) ) return Cutscene.CUTSCENE_END # Collect fighters var playerFighters:Array[BattleFighter] = [] var aiFighters:Array[BattleFighter] = [] for fighter:BattleFighter in BATTLE.fighterMap.values(): if !fighter || !fighter.canPlayerMakeDecision(): continue playerFighters.append(fighter) for fighter:BattleFighter in BATTLE.fighterMap.values(): if !fighter || !fighter.canMakeDecision(): continue if fighter in playerFighters: continue aiFighters.append(fighter) # Gather decisions var decisions:Array[BattleDecision] = [] var playerDecisions = await BATTLE.battleScene.getBattleDecisions(playerFighters) decisions.append_array(playerDecisions) for fighter in aiFighters: var decision = fighter.getAIDecision() if decision != null: decisions.append(decision) # Sort by priority decisions.shuffle() decisions.sort_custom(func(a:BattleDecision, b:BattleDecision) -> int: var pa = a.getPriority() var pb = b.getPriority() if pa > pb: return -1 elif pa < pb: return 1 else: return 0 ) for decision in decisions: params['cutscene'].addCallable(getBattleDecisionCallable(decision)) params['cutscene'].addCallable(getPlayerDecisionCallable()) return Cutscene.CUTSCENE_CONTINUE static func getPlayerDecisionCallable() -> Dictionary: return { 'function': playerDecisionCallable, }