Change battle actions to use battle decisions instead.

This commit is contained in:
2026-01-15 19:09:46 -06:00
parent 3b7de160dc
commit 274cbef780
15 changed files with 173 additions and 41 deletions

View File

@@ -46,8 +46,7 @@ func startBattle(params) -> void:
# Initial cutscene elements. In future I may need to make this editable
# somehow?
for fighter:BattleFighter in params['fighters'].values():
battleCutscene.addCallable(BattleCutsceneAction.getPlayerDecisionCallable(fighter))
battleCutscene.addCallable(BattleCutsceneAction.getPlayerDecisionCallable())
# Emit signals
active = true
@@ -56,7 +55,15 @@ func startBattle(params) -> void:
# Start running the battle cutscene.
if !battleCutscene.running:
battleCutscene.start()
battleCutscene.start()# Should this await?
func getFighterAtPosition(battlePos:BattlePosition) -> BattleFighter:
return fighterMap.get(battlePos, null)
func getPositionOfFighter(fighter:BattleFighter) -> BattlePosition:
for pos in fighterMap.keys():
if fighterMap[pos] == fighter:
return pos
assert(false)
return BattlePosition.LEFT_TOP_BACK

View File

@@ -4,7 +4,6 @@ class_name BattleScene extends Node3D
func _init() ->void:
BATTLE.battleScene = self
BATTLE.battleStarted.connect(onBattleStarted)
func onBattleStarted() -> void:

View File

@@ -0,0 +1,11 @@
class_name BattleAction
var speedModifier:float
func _init(params:Dictionary) -> void:
self.speedModifier = params.get("speedModifier", 1.0)
func perform(params:Dictionary) -> void:
assert(params.has("user"))
assert(params.has("target"))
pass

View File

@@ -0,0 +1 @@
uid://ref2clyh0nc2

View File

@@ -0,0 +1,13 @@
class_name BattleDecision
var action:BattleAction
var user:BattleFighter
var target:BattleFighter
func _init(_action:BattleAction, _user:BattleFighter, _target:BattleFighter) -> void:
action = _action
user = _user
target = _target
func getPriority() -> float:
return 1.0

View File

@@ -0,0 +1 @@
uid://bhdv13g6t1h01

View File

@@ -0,0 +1,50 @@
class_name BattleMove extends BattleAction
enum MoveType {
PHYSICAL,
ABILITY,
MAGICAL,
}
var name:String
var power:int
var mpCost:int
var accuracy:float
var moveType:MoveType
var fieldUse:bool
func _init(params:Dictionary) -> void:
self.name = params.get("name", "Unknown Move")
self.power = params.get("power", 0)
self.mpCost = params.get("mpCost", 0)
self.speedModifier = params.get("speedModifier", 1.0)
self.accuracy = params.get("accuracy", 1.0)
self.moveType = params.get("moveType", MoveType.PHYSICAL)
self.fieldUse = params.get("fieldUse", false)
func getPriority(_fighter:BattleFighter) -> float:
return 1.0
# Moves
static var MOVE_PUNCH = BattleMove.new({
"name": "Punch",
"power": 15,
"accuracy": 0.95,
"moveType": MoveType.PHYSICAL
})
static var MOVE_FIRE1 = BattleMove.new({
"name": "Fire",
"power": 25,
"mpCost": 5,
"accuracy": 0.9,
"moveType": MoveType.MAGICAL
})
static var MOVE_HEAL1 = BattleMove.new({
"name": "Heal",
"power": -20,
"mpCost": 8,
"accuracy": 1.0,
"moveType": MoveType.ABILITY
})

View File

@@ -0,0 +1 @@
uid://gb08hhwk0paw

View File

@@ -102,8 +102,8 @@ func mpRestore(amount:int) -> void:
mp = min(mp + amount, maxMp)
mpChanged.emit(amount)
func isCrit() -> bool:
# 10% chance of a crit
var chance = 10 + min(luck * 5, 60)
var roll = randi() % 100
return roll < chance
func isPlayerControlled() -> bool:
return controller == FighterController.PLAYER
func getAIDecision() -> BattleDecision:
return null

View File

@@ -1,4 +1,4 @@
class_name BattleMove
class_name BattleMove extends BattleAction
enum MoveType {
PHYSICAL,
@@ -9,24 +9,19 @@ enum MoveType {
var name:String
var power:int
var mpCost:int
var speedModifier:float
var accuracy:float
var moveType:MoveType
var fieldUse:bool
func _init(params:Dictionary) -> void:
super(params)
self.name = params.get("name", "Unknown Move")
self.power = params.get("power", 0)
self.mpCost = params.get("mpCost", 0)
self.speedModifier = params.get("speedModifier", 1.0)
self.accuracy = params.get("accuracy", 1.0)
self.moveType = params.get("moveType", MoveType.PHYSICAL)
self.fieldUse = params.get("fieldUse", false)
func start(_params:Dictionary) -> void:
# Implement move execution logic here
await UI.TEXTBOX.setTextAndWait("Action")
# Moves
static var MOVE_PUNCH = BattleMove.new({
"name": "Punch",

View File

@@ -1 +1 @@
uid://gb08hhwk0paw
uid://bgq0u537pt5lm

View File

@@ -1,11 +1,10 @@
class_name ActionBox extends GridContainer
const BattleMove = preload("res://battle/fighter/BattleMove.gd")
@export var btnAttack:Button
@export var btnMagic:Button
@export var btnItem:Button
signal decisionMade(move:BattleMove)
signal decisionMade(move:BattleDecision)
func _ready() -> void:
btnAttack.pressed.connect(onAttackPressed)
@@ -15,11 +14,11 @@ func _ready() -> void:
func onAttackPressed() -> void:
print("Attack button pressed")
decisionMade.emit(BattleMove.MOVE_PUNCH)
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_PUNCH, null, null))
func onMagicPressed() -> void:
print("Magic button pressed")
decisionMade.emit(BattleMove.MOVE_FIRE1)
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_FIRE1, null, null))
func onItemPressed() -> void:
print("Item button pressed")

View File

@@ -1,14 +1,62 @@
class_name BattleAction
const BattleFighter = preload("res://battle/fighter/BattleFighter.gd")
class_name BattleCutsceneAction
static func playerDecisionCallable(_params:Dictionary) -> int:
BATTLE.battleScene.actionBox.visible = true
var move = await BATTLE.battleScene.actionBox.decisionMade
BATTLE.battleScene.actionBox.visible = false
static func battleDecisionCallable(_params:Dictionary) -> int:
print("Battle action executed.")
return Cutscene.CUTSCENE_CONTINUE
static func getPlayerDecisionCallable(fighter:BattleFighter) -> Dictionary:
static func getBattleDecisionCallable(decision:BattleDecision) -> Dictionary:
return {
"function": playerDecisionCallable,
"fighter": fighter
"function": battleDecisionCallable,
"decision": decision
}
static func playerDecisionCallable(_params:Dictionary) -> int:
var decisions:Array[BattleDecision] = []
for fighter:BattleFighter in BATTLE.fighterMap.values():
if !fighter || !fighter.isPlayerControlled():
continue
# Handle player decision
BATTLE.battleScene.actionBox.visible = true
var decision = await BATTLE.battleScene.actionBox.decisionMade
BATTLE.battleScene.actionBox.visible = false
if decision == null:
continue
decisions.append(decision)
# AI decisions
for fighter:BattleFighter in BATTLE.fighterMap.values():
if !fighter || fighter.isPlayerControlled():
continue
var decision = fighter.getAIDecision()
if decision == null:
continue
decisions.append(decision)
# Here I could do something like cutscene specific logic?
# Prioritize moves
decisions.shuffle()# Randomizes for moves that have equal chance of happening
decisions.sort_custom(func(a:BattleDecision, b:BattleDecision) -> int:
var priorityA = a.getPriority()
var priorityB = b.getPriority()
if priorityA > priorityB:
return -1
elif priorityA < priorityB:
return 1
else:
return 0
)
# Turn into cutscene actions.
for decision in decisions:
_params['cutscene'].addCallable(BattleCutsceneAction.getBattleDecisionCallable(decision))
return Cutscene.CUTSCENE_CONTINUE
static func getPlayerDecisionCallable() -> Dictionary:
return {
"function": playerDecisionCallable
}

View File

@@ -7,17 +7,23 @@ class_name RootScene extends Node3D
@export var currentScene:Node = null
func _enter_tree() -> void:
SCENE.sceneChanged.connect(onSceneChange)
SCENE.setScene(SceneSingleton.SceneType.INITIAL)
# SCENE.sceneChanged.connect(onSceneChange)
# SCENE.setScene(SceneSingleton.SceneType.INITIAL)
# SCENE.setScene(SceneSingleton.SceneType.BATTLE)
# # Wait a frame
# await get_tree().process_frame
# BATTLE.startBattle({
# 'fighters': {
# BATTLE.BattlePosition.RIGHT_TOP_FRONT: PartySingleton.PARTY_JOHN,
# }
# })
SCENE.setScene(SceneSingleton.SceneType.BATTLE)
# Wait a frame
await get_tree().process_frame
var testEnemy = BattleFighter.new({
'controller': BattleFighter.FighterController.AI
})
BATTLE.startBattle({
'fighters': {
# Test fighters
BATTLE.BattlePosition.RIGHT_MIDDLE_FRONT: PartySingleton.PARTY_JOHN,
BATTLE.BattlePosition.LEFT_MIDDLE_FRONT: testEnemy
}
})
func _exit_tree() -> void:
push_error("RootScene should not be removed from the scene tree. This is a bug.")

View File

@@ -31,3 +31,4 @@ visible = false
[node name="CurrentScene" type="Node" parent="."]
[node name="RootUI" parent="." instance=ExtResource("6_ajii0")]
visible = false