Change battle actions to use battle decisions instead.
This commit is contained in:
@@ -46,8 +46,7 @@ func startBattle(params) -> void:
|
|||||||
|
|
||||||
# Initial cutscene elements. In future I may need to make this editable
|
# Initial cutscene elements. In future I may need to make this editable
|
||||||
# somehow?
|
# somehow?
|
||||||
for fighter:BattleFighter in params['fighters'].values():
|
battleCutscene.addCallable(BattleCutsceneAction.getPlayerDecisionCallable())
|
||||||
battleCutscene.addCallable(BattleCutsceneAction.getPlayerDecisionCallable(fighter))
|
|
||||||
|
|
||||||
# Emit signals
|
# Emit signals
|
||||||
active = true
|
active = true
|
||||||
@@ -56,7 +55,15 @@ func startBattle(params) -> void:
|
|||||||
|
|
||||||
# Start running the battle cutscene.
|
# Start running the battle cutscene.
|
||||||
if !battleCutscene.running:
|
if !battleCutscene.running:
|
||||||
battleCutscene.start()
|
battleCutscene.start()# Should this await?
|
||||||
|
|
||||||
func getFighterAtPosition(battlePos:BattlePosition) -> BattleFighter:
|
func getFighterAtPosition(battlePos:BattlePosition) -> BattleFighter:
|
||||||
return fighterMap.get(battlePos, null)
|
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
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ class_name BattleScene extends Node3D
|
|||||||
|
|
||||||
func _init() ->void:
|
func _init() ->void:
|
||||||
BATTLE.battleScene = self
|
BATTLE.battleScene = self
|
||||||
|
|
||||||
BATTLE.battleStarted.connect(onBattleStarted)
|
BATTLE.battleStarted.connect(onBattleStarted)
|
||||||
|
|
||||||
func onBattleStarted() -> void:
|
func onBattleStarted() -> void:
|
||||||
|
|||||||
11
battle/action/BattleAction.gd
Normal file
11
battle/action/BattleAction.gd
Normal 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
|
||||||
1
battle/action/BattleAction.gd.uid
Normal file
1
battle/action/BattleAction.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ref2clyh0nc2
|
||||||
13
battle/action/BattleDecision.gd
Normal file
13
battle/action/BattleDecision.gd
Normal 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
|
||||||
1
battle/action/BattleDecision.gd.uid
Normal file
1
battle/action/BattleDecision.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bhdv13g6t1h01
|
||||||
50
battle/action/BattleMove.gd
Normal file
50
battle/action/BattleMove.gd
Normal 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
|
||||||
|
})
|
||||||
1
battle/action/BattleMove.gd.uid
Normal file
1
battle/action/BattleMove.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://gb08hhwk0paw
|
||||||
@@ -102,8 +102,8 @@ func mpRestore(amount:int) -> void:
|
|||||||
mp = min(mp + amount, maxMp)
|
mp = min(mp + amount, maxMp)
|
||||||
mpChanged.emit(amount)
|
mpChanged.emit(amount)
|
||||||
|
|
||||||
func isCrit() -> bool:
|
func isPlayerControlled() -> bool:
|
||||||
# 10% chance of a crit
|
return controller == FighterController.PLAYER
|
||||||
var chance = 10 + min(luck * 5, 60)
|
|
||||||
var roll = randi() % 100
|
func getAIDecision() -> BattleDecision:
|
||||||
return roll < chance
|
return null
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class_name BattleMove
|
class_name BattleMove extends BattleAction
|
||||||
|
|
||||||
enum MoveType {
|
enum MoveType {
|
||||||
PHYSICAL,
|
PHYSICAL,
|
||||||
@@ -9,24 +9,19 @@ enum MoveType {
|
|||||||
var name:String
|
var name:String
|
||||||
var power:int
|
var power:int
|
||||||
var mpCost:int
|
var mpCost:int
|
||||||
var speedModifier:float
|
|
||||||
var accuracy:float
|
var accuracy:float
|
||||||
var moveType:MoveType
|
var moveType:MoveType
|
||||||
var fieldUse:bool
|
var fieldUse:bool
|
||||||
|
|
||||||
func _init(params:Dictionary) -> void:
|
func _init(params:Dictionary) -> void:
|
||||||
|
super(params)
|
||||||
self.name = params.get("name", "Unknown Move")
|
self.name = params.get("name", "Unknown Move")
|
||||||
self.power = params.get("power", 0)
|
self.power = params.get("power", 0)
|
||||||
self.mpCost = params.get("mpCost", 0)
|
self.mpCost = params.get("mpCost", 0)
|
||||||
self.speedModifier = params.get("speedModifier", 1.0)
|
|
||||||
self.accuracy = params.get("accuracy", 1.0)
|
self.accuracy = params.get("accuracy", 1.0)
|
||||||
self.moveType = params.get("moveType", MoveType.PHYSICAL)
|
self.moveType = params.get("moveType", MoveType.PHYSICAL)
|
||||||
self.fieldUse = params.get("fieldUse", false)
|
self.fieldUse = params.get("fieldUse", false)
|
||||||
|
|
||||||
func start(_params:Dictionary) -> void:
|
|
||||||
# Implement move execution logic here
|
|
||||||
await UI.TEXTBOX.setTextAndWait("Action")
|
|
||||||
|
|
||||||
# Moves
|
# Moves
|
||||||
static var MOVE_PUNCH = BattleMove.new({
|
static var MOVE_PUNCH = BattleMove.new({
|
||||||
"name": "Punch",
|
"name": "Punch",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
uid://gb08hhwk0paw
|
uid://bgq0u537pt5lm
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
class_name ActionBox extends GridContainer
|
class_name ActionBox extends GridContainer
|
||||||
const BattleMove = preload("res://battle/fighter/BattleMove.gd")
|
|
||||||
|
|
||||||
@export var btnAttack:Button
|
@export var btnAttack:Button
|
||||||
@export var btnMagic:Button
|
@export var btnMagic:Button
|
||||||
@export var btnItem:Button
|
@export var btnItem:Button
|
||||||
|
|
||||||
signal decisionMade(move:BattleMove)
|
signal decisionMade(move:BattleDecision)
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
btnAttack.pressed.connect(onAttackPressed)
|
btnAttack.pressed.connect(onAttackPressed)
|
||||||
@@ -15,11 +14,11 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func onAttackPressed() -> void:
|
func onAttackPressed() -> void:
|
||||||
print("Attack button pressed")
|
print("Attack button pressed")
|
||||||
decisionMade.emit(BattleMove.MOVE_PUNCH)
|
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_PUNCH, null, null))
|
||||||
|
|
||||||
func onMagicPressed() -> void:
|
func onMagicPressed() -> void:
|
||||||
print("Magic button pressed")
|
print("Magic button pressed")
|
||||||
decisionMade.emit(BattleMove.MOVE_FIRE1)
|
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_FIRE1, null, null))
|
||||||
|
|
||||||
func onItemPressed() -> void:
|
func onItemPressed() -> void:
|
||||||
print("Item button pressed")
|
print("Item button pressed")
|
||||||
|
|||||||
@@ -1,14 +1,62 @@
|
|||||||
class_name BattleAction
|
class_name BattleCutsceneAction
|
||||||
const BattleFighter = preload("res://battle/fighter/BattleFighter.gd")
|
|
||||||
|
|
||||||
static func playerDecisionCallable(_params:Dictionary) -> int:
|
static func battleDecisionCallable(_params:Dictionary) -> int:
|
||||||
BATTLE.battleScene.actionBox.visible = true
|
print("Battle action executed.")
|
||||||
var move = await BATTLE.battleScene.actionBox.decisionMade
|
|
||||||
BATTLE.battleScene.actionBox.visible = false
|
|
||||||
return Cutscene.CUTSCENE_CONTINUE
|
return Cutscene.CUTSCENE_CONTINUE
|
||||||
|
|
||||||
static func getPlayerDecisionCallable(fighter:BattleFighter) -> Dictionary:
|
|
||||||
|
static func getBattleDecisionCallable(decision:BattleDecision) -> Dictionary:
|
||||||
return {
|
return {
|
||||||
"function": playerDecisionCallable,
|
"function": battleDecisionCallable,
|
||||||
"fighter": fighter
|
"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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,23 @@ class_name RootScene extends Node3D
|
|||||||
@export var currentScene:Node = null
|
@export var currentScene:Node = null
|
||||||
|
|
||||||
func _enter_tree() -> void:
|
func _enter_tree() -> void:
|
||||||
SCENE.sceneChanged.connect(onSceneChange)
|
# SCENE.sceneChanged.connect(onSceneChange)
|
||||||
SCENE.setScene(SceneSingleton.SceneType.INITIAL)
|
# SCENE.setScene(SceneSingleton.SceneType.INITIAL)
|
||||||
|
|
||||||
# SCENE.setScene(SceneSingleton.SceneType.BATTLE)
|
SCENE.setScene(SceneSingleton.SceneType.BATTLE)
|
||||||
# # Wait a frame
|
# Wait a frame
|
||||||
# await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
# BATTLE.startBattle({
|
|
||||||
# 'fighters': {
|
var testEnemy = BattleFighter.new({
|
||||||
# BATTLE.BattlePosition.RIGHT_TOP_FRONT: PartySingleton.PARTY_JOHN,
|
'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:
|
func _exit_tree() -> void:
|
||||||
push_error("RootScene should not be removed from the scene tree. This is a bug.")
|
push_error("RootScene should not be removed from the scene tree. This is a bug.")
|
||||||
|
|||||||
@@ -31,3 +31,4 @@ visible = false
|
|||||||
[node name="CurrentScene" type="Node" parent="."]
|
[node name="CurrentScene" type="Node" parent="."]
|
||||||
|
|
||||||
[node name="RootUI" parent="." instance=ExtResource("6_ajii0")]
|
[node name="RootUI" parent="." instance=ExtResource("6_ajii0")]
|
||||||
|
visible = false
|
||||||
|
|||||||
Reference in New Issue
Block a user