baddle
This commit is contained in:
@@ -2,9 +2,48 @@ class_name BattleScene extends Node3D
|
|||||||
|
|
||||||
@export var actionBox:ActionBox = null
|
@export var actionBox:ActionBox = null
|
||||||
|
|
||||||
|
signal neverEmitted
|
||||||
|
|
||||||
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:
|
||||||
pass
|
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
|
||||||
|
break
|
||||||
|
elif action == ActionBox.Action.ATTACK:
|
||||||
|
var targets = await _getTargets(fighter, fighter.movePrimary)
|
||||||
|
|
||||||
|
actionBox.visible = false
|
||||||
|
|
||||||
|
if decision != null:
|
||||||
|
decisions.append(decision)
|
||||||
|
|
||||||
|
# Return the made decision
|
||||||
|
return decisions
|
||||||
|
|
||||||
|
func _getTargets(fighter:BattleFighter, move:BattleAction) -> Array[BattleFighter]:
|
||||||
|
print("Determining target")
|
||||||
|
await neverEmitted
|
||||||
|
return []
|
||||||
@@ -1,11 +1,22 @@
|
|||||||
class_name BattleAction
|
class_name BattleAction
|
||||||
|
|
||||||
var speedModifier:float
|
var speedModifier:float
|
||||||
|
var canTargetMultiple:bool
|
||||||
|
var canTargetEnemy:bool
|
||||||
|
var canTargetAlly:bool
|
||||||
|
var preferAlly:bool
|
||||||
|
|
||||||
func _init(params:Dictionary) -> void:
|
func _init(params:Dictionary) -> void:
|
||||||
self.speedModifier = params.get("speedModifier", 1.0)
|
self.speedModifier = params.get("speedModifier", 1.0)
|
||||||
|
self.canTargetMultiple = params.get("canTargetMultiple", false)
|
||||||
|
self.canTargetEnemy = params.get("canTargetEnemy", true)
|
||||||
|
self.canTargetAlly = params.get("canTargetAlly", true)
|
||||||
|
self.preferAlly = params.get("preferAlly", false)
|
||||||
|
|
||||||
func perform(params:Dictionary) -> void:
|
func perform(params:Dictionary) -> void:
|
||||||
assert(params.has("user"))
|
assert(params.has("user"))
|
||||||
assert(params.has("target"))
|
assert(params.has("targets"))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
func canFighterUse(fighter:BattleFighter) -> bool:
|
||||||
|
return true
|
||||||
@@ -2,12 +2,15 @@ class_name BattleDecision
|
|||||||
|
|
||||||
var action:BattleAction
|
var action:BattleAction
|
||||||
var user:BattleFighter
|
var user:BattleFighter
|
||||||
var target:BattleFighter
|
var targets:Array[BattleFighter]
|
||||||
|
|
||||||
func _init(_action:BattleAction, _user:BattleFighter, _target:BattleFighter) -> void:
|
func _init(_action:BattleAction, _user:BattleFighter, _targets:Array[BattleFighter]) -> void:
|
||||||
action = _action
|
action = _action
|
||||||
user = _user
|
user = _user
|
||||||
target = _target
|
targets = _targets
|
||||||
|
|
||||||
func getPriority() -> float:
|
func getPriority() -> float:
|
||||||
return 1.0
|
return 1.0
|
||||||
|
|
||||||
|
func execute(cutscene:Cutscene) -> void:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ func perform(params:Dictionary) -> void:
|
|||||||
super.perform(params)
|
super.perform(params)
|
||||||
|
|
||||||
var user:BattleFighter = params.get("user")
|
var user:BattleFighter = params.get("user")
|
||||||
var target:BattleFighter = params.get("target")
|
var targets:Array[BattleFighter] = params.get("targets")
|
||||||
@@ -32,12 +32,13 @@ func perform(params:Dictionary):
|
|||||||
super.perform(params)
|
super.perform(params)
|
||||||
|
|
||||||
var user:BattleFighter = params.get("user")
|
var user:BattleFighter = params.get("user")
|
||||||
var target:BattleFighter = params.get("target")
|
var targets:Array[BattleFighter] = params.get("targets")
|
||||||
|
|
||||||
# What to do if target is dead?
|
# What to do if target is dead?
|
||||||
if target.status == BattleFighter.Status.DEAD:
|
for target in targets:
|
||||||
print("Target is already dead. Move has no effect.")
|
if target.status == BattleFighter.Status.DEAD:
|
||||||
assert(false)
|
print("Target is already dead. Move has no effect.")
|
||||||
|
assert(false)
|
||||||
|
|
||||||
# TODO: Determine damage
|
# TODO: Determine damage
|
||||||
var damage:int = 0
|
var damage:int = 0
|
||||||
@@ -51,9 +52,19 @@ func perform(params:Dictionary):
|
|||||||
|
|
||||||
if isCrit:
|
if isCrit:
|
||||||
print("CRITICAL HIT!")
|
print("CRITICAL HIT!")
|
||||||
target.damage(damage, isCrit)
|
for target in targets:
|
||||||
|
target.damage(damage, isCrit)
|
||||||
print("DAMAGE DONE")
|
print("DAMAGE DONE")
|
||||||
|
|
||||||
|
func canFighterUse(fighter:BattleFighter) -> bool:
|
||||||
|
if !super.canFighterUse(fighter):
|
||||||
|
return false
|
||||||
|
|
||||||
|
if fighter.mp < self.mpCost:
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
# Moves
|
# Moves
|
||||||
static var MOVE_PUNCH = BattleMove.new({
|
static var MOVE_PUNCH = BattleMove.new({
|
||||||
"name": "Punch",
|
"name": "Punch",
|
||||||
@@ -67,7 +78,8 @@ static var MOVE_FIRE1 = BattleMove.new({
|
|||||||
"power": 25,
|
"power": 25,
|
||||||
"mpCost": 5,
|
"mpCost": 5,
|
||||||
"accuracy": 0.9,
|
"accuracy": 0.9,
|
||||||
"moveType": MoveType.MAGICAL
|
"moveType": MoveType.MAGICAL,
|
||||||
|
"canTargetMultiple": true
|
||||||
})
|
})
|
||||||
|
|
||||||
static var MOVE_HEAL1 = BattleMove.new({
|
static var MOVE_HEAL1 = BattleMove.new({
|
||||||
@@ -75,5 +87,7 @@ static var MOVE_HEAL1 = BattleMove.new({
|
|||||||
"power": -20,
|
"power": -20,
|
||||||
"mpCost": 8,
|
"mpCost": 8,
|
||||||
"accuracy": 1.0,
|
"accuracy": 1.0,
|
||||||
"moveType": MoveType.ABILITY
|
"moveType": MoveType.ABILITY,
|
||||||
|
"canTargetMultiple": true,
|
||||||
|
"preferAlly": true
|
||||||
})
|
})
|
||||||
@@ -6,7 +6,7 @@ enum Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum FighterTeam {
|
enum FighterTeam {
|
||||||
PLAYER,
|
ALLY,
|
||||||
ENEMY
|
ENEMY
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,4 +106,12 @@ func isPlayerControlled() -> bool:
|
|||||||
return controller == FighterController.PLAYER
|
return controller == FighterController.PLAYER
|
||||||
|
|
||||||
func getAIDecision() -> BattleDecision:
|
func getAIDecision() -> BattleDecision:
|
||||||
|
if !canMakeDecision():
|
||||||
|
return null
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
func canMakeDecision() -> bool:
|
||||||
|
return status != Status.DEAD
|
||||||
|
|
||||||
|
func canPlayerMakeDecision() -> bool:
|
||||||
|
return isPlayerControlled() && canMakeDecision()
|
||||||
@@ -1,25 +1,40 @@
|
|||||||
class_name ActionBox extends GridContainer
|
class_name ActionBox extends GridContainer
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
ATTACK,
|
||||||
|
MAGIC,
|
||||||
|
ITEM,
|
||||||
|
BACK
|
||||||
|
}
|
||||||
|
|
||||||
@export var btnAttack:Button
|
@export var btnAttack:Button
|
||||||
@export var btnMagic:Button
|
@export var btnMagic:Button
|
||||||
@export var btnItem:Button
|
@export var btnItem:Button
|
||||||
|
@export var btnBack:Button
|
||||||
|
|
||||||
signal decisionMade(move:BattleDecision)
|
signal action(action:Action)
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
btnAttack.pressed.connect(onAttackPressed)
|
btnAttack.pressed.connect(func():
|
||||||
btnMagic.pressed.connect(onMagicPressed)
|
action.emit(Action.ATTACK)
|
||||||
btnItem.pressed.connect(onItemPressed)
|
)
|
||||||
|
btnMagic.pressed.connect(func():
|
||||||
|
action.emit(Action.MAGIC)
|
||||||
|
)
|
||||||
|
btnItem.pressed.connect(func():
|
||||||
|
action.emit(Action.ITEM)
|
||||||
|
)
|
||||||
|
btnBack.pressed.connect(func():
|
||||||
|
action.emit(Action.BACK)
|
||||||
|
)
|
||||||
self.visible = false
|
self.visible = false
|
||||||
|
|
||||||
func onAttackPressed() -> void:
|
func getAction(fighter:BattleFighter) -> Action:
|
||||||
print("Attack button pressed")
|
btnAttack.disabled = fighter.movePrimary == null || !fighter.movePrimary.canFighterUse(fighter)
|
||||||
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_PUNCH, null, null))
|
btnMagic.disabled = fighter.movesMagical.size() == 0
|
||||||
|
btnItem.disabled = false # TODO: check if items available?
|
||||||
func onMagicPressed() -> void:
|
|
||||||
print("Magic button pressed")
|
|
||||||
decisionMade.emit(BattleDecision.new(BattleMove.MOVE_FIRE1, null, null))
|
|
||||||
|
|
||||||
func onItemPressed() -> void:
|
# TODO: Update cursor position to first enabled button
|
||||||
print("Item button pressed")
|
|
||||||
decisionMade.emit(null)
|
var act = await action
|
||||||
|
return act
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[ext_resource type="Script" uid="uid://27274005hbgh" path="res://battle/ui/ActionBox.gd" id="1_w5s71"]
|
[ext_resource type="Script" uid="uid://27274005hbgh" path="res://battle/ui/ActionBox.gd" id="1_w5s71"]
|
||||||
|
|
||||||
[node name="ActionBox" type="GridContainer" node_paths=PackedStringArray("btnAttack", "btnMagic", "btnItem")]
|
[node name="ActionBox" type="GridContainer" node_paths=PackedStringArray("btnAttack", "btnMagic", "btnItem", "btnBack")]
|
||||||
anchors_preset = 3
|
anchors_preset = 3
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
@@ -17,6 +17,7 @@ script = ExtResource("1_w5s71")
|
|||||||
btnAttack = NodePath("Attack")
|
btnAttack = NodePath("Attack")
|
||||||
btnMagic = NodePath("Magic")
|
btnMagic = NodePath("Magic")
|
||||||
btnItem = NodePath("Items")
|
btnItem = NodePath("Items")
|
||||||
|
btnBack = NodePath("Back")
|
||||||
metadata/_custom_type_script = "uid://27274005hbgh"
|
metadata/_custom_type_script = "uid://27274005hbgh"
|
||||||
|
|
||||||
[node name="Attack" type="Button" parent="."]
|
[node name="Attack" type="Button" parent="."]
|
||||||
@@ -31,6 +32,6 @@ text = "Magic"
|
|||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Items"
|
text = "Items"
|
||||||
|
|
||||||
[node name="idk" type="Button" parent="."]
|
[node name="Back" type="Button" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "idk"
|
text = "Back"
|
||||||
|
|||||||
@@ -37,29 +37,31 @@ static func playerDecisionCallable(_params:Dictionary) -> int:
|
|||||||
print("All enemies defeated! Victory!")
|
print("All enemies defeated! Victory!")
|
||||||
assert(false)
|
assert(false)
|
||||||
|
|
||||||
# OK we are actually fighting.
|
# Determine fighters and whether they're AI or player controlled
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Get decisions
|
||||||
var decisions:Array[BattleDecision] = []
|
var decisions:Array[BattleDecision] = []
|
||||||
|
var playerDecisions = await BATTLE.battleScene.getBattleDecisions(playerFighters)
|
||||||
|
decisions.append_array(playerDecisions)
|
||||||
|
|
||||||
for fighter:BattleFighter in BATTLE.fighterMap.values():
|
for fighter in aiFighters:
|
||||||
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()
|
var decision = fighter.getAIDecision()
|
||||||
if decision == null:
|
if decision != null:
|
||||||
continue
|
decisions.append(decision)
|
||||||
decisions.append(decision)
|
|
||||||
|
|
||||||
# Here I could do something like cutscene specific logic?
|
# Here I could do something like cutscene specific logic?
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ class_name PartySingleton extends Node
|
|||||||
|
|
||||||
static var PARTY_JOHN = PartyMember.new({
|
static var PARTY_JOHN = PartyMember.new({
|
||||||
'name': "John",
|
'name': "John",
|
||||||
'team': BattleFighter.FighterTeam.PLAYER,
|
'team': BattleFighter.FighterTeam.ALLY,
|
||||||
"maxHealth": 9999999999,
|
"maxHealth": 9999999999,
|
||||||
"movePrimary": BattleMove.MOVE_PUNCH,
|
"movePrimary": BattleMove.MOVE_PUNCH,
|
||||||
"movesMagical": [ BattleMove.MOVE_FIRE1 ],
|
"movesMagical": [ BattleMove.MOVE_FIRE1 ],
|
||||||
|
|||||||
Reference in New Issue
Block a user