This commit is contained in:
2026-01-11 19:32:12 -06:00
parent 6ecbc33cc2
commit 561ab5a983
19 changed files with 245 additions and 203 deletions

View File

@@ -1,7 +1,59 @@
class_name BattleSingleton extends Node
const BattleCutsceneAction = preload("res://battle/cutscene/BattleCutsceneAction.gd")
enum BattlePosition {
LEFT_TOP_BACK,
LEFT_TOP_FRONT,
LEFT_MIDDLE_BACK,
LEFT_MIDDLE_FRONT,
LEFT_BOTTOM_BACK,
LEFT_BOTTOM_FRONT,
RIGHT_TOP_BACK,
RIGHT_TOP_FRONT,
RIGHT_MIDDLE_BACK,
RIGHT_MIDDLE_FRONT,
RIGHT_BOTTOM_BACK,
RIGHT_BOTTOM_FRONT
}
# Battle State
var active:bool = false
var fighterMap:Dictionary[BattlePosition, BattleFighter] = {}
var battleCutscene:Cutscene = null
# Non-guarantees
var battleScene:BattleScene = null
# Signals
signal battleStarted
signal battleFightersChanged
func startBattle(params) -> void:
assert(battleScene != null)
battleScene.startBattle(params)
assert(params.has('fighters'))
assert(!active)
# Get the cutscene (or create a default one).
battleCutscene = params.get('cutscene', Cutscene.new())
# Update fighters for each fighter scene.
for pos in BattlePosition.values():
var fighterOrNull = params['fighters'].get(pos, null)
fighterMap[pos] = fighterOrNull
# 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))
# Emit signals
active = true
battleStarted.emit()
battleFightersChanged.emit()
# Start running the battle cutscene.
if !battleCutscene.running:
battleCutscene.start()
func getFighterAtPosition(battlePos:BattlePosition) -> BattleFighter:
return fighterMap.get(battlePos, null)

View File

@@ -1,145 +1,11 @@
class_name BattleScene extends BattleFighterScene
const CutsceneBattleAction = preload("res://cutscene/battle/CutsceneBattleAction.gd")
enum BattlePosition {
LEFT_TOP_BACK,
LEFT_TOP_FRONT,
LEFT_MIDDLE_BACK,
LEFT_MIDDLE_FRONT,
LEFT_BOTTOM_BACK,
LEFT_BOTTOM_FRONT,
RIGHT_TOP_BACK,
RIGHT_TOP_FRONT,
RIGHT_MIDDLE_BACK,
RIGHT_MIDDLE_FRONT,
RIGHT_BOTTOM_BACK,
RIGHT_BOTTOM_FRONT
}
var active:bool = false
var fighterMap:Dictionary[BattlePosition, BattleFighterScene] = {}
class_name BattleScene extends Node3D
@export var actionBox:ActionBox = null
@export var fighterTopLeftBack:BattleFighterScene = null:
get:
return fighterMap.get(BattlePosition.LEFT_TOP_BACK, null)
set(value):
fighterMap[BattlePosition.LEFT_TOP_BACK] = value
@export var fighterTopLeftFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.LEFT_TOP_FRONT, null)
set(value):
fighterMap[BattlePosition.LEFT_TOP_FRONT] = value
@export var fighterMiddleLeftBack:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.LEFT_MIDDLE_BACK, null)
set(value):
fighterMap[BattlePosition.LEFT_MIDDLE_BACK] = value
@export var fighterMiddleLeftFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.LEFT_MIDDLE_FRONT, null)
set(value):
fighterMap[BattlePosition.LEFT_MIDDLE_FRONT] = value
@export var fighterBottomLeftBack:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.LEFT_BOTTOM_BACK, null)
set(value):
fighterMap[BattlePosition.LEFT_BOTTOM_BACK] = value
@export var fighterBottomLeftFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.LEFT_BOTTOM_FRONT, null)
set(value):
fighterMap[BattlePosition.LEFT_BOTTOM_FRONT] = value
@export var fighterTopRightBack:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_TOP_BACK, null)
set(value):
fighterMap[BattlePosition.RIGHT_TOP_BACK] = value
@export var fighterTopRightFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_TOP_FRONT, null)
set(value):
fighterMap[BattlePosition.RIGHT_TOP_FRONT] = value
@export var fighterMiddleRightBack:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_MIDDLE_BACK, null)
set(value):
fighterMap[BattlePosition.RIGHT_MIDDLE_BACK] = value
@export var fighterMiddleRightFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_MIDDLE_FRONT, null)
set(value):
fighterMap[BattlePosition.RIGHT_MIDDLE_FRONT] = value
@export var fighterBottomRightBack:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_BOTTOM_BACK, null)
set(value):
fighterMap[BattlePosition.RIGHT_BOTTOM_BACK] = value
@export var fighterBottomRightFront:BattleFighterScene:
get:
return fighterMap.get(BattlePosition.RIGHT_BOTTOM_FRONT, null)
set(value):
fighterMap[BattlePosition.RIGHT_BOTTOM_FRONT] = value
func _init() ->void:
BATTLE.battleScene = self
BATTLE.battleStarted.connect(onBattleStarted)
func onBattleStarted() -> void:
pass
func getFigheterAtPosition(battlePos:BattlePosition) -> BattleFighterScene:
return fighterMap.get(battlePos, null)
func getPositionForFighterScene(fighterScene:BattleFighterScene) -> BattlePosition:
for battlePos in fighterMap.keys():
var scene:BattleFighterScene = fighterMap[battlePos]
if scene == fighterScene:
return battlePos
assert(false)
return BattlePosition.LEFT_TOP_BACK
func getPositionForFighter(fighter:BattleFighter) -> BattlePosition:
for battlePos in fighterMap.keys():
var fighterScene:BattleFighterScene = fighterMap[battlePos]
if fighterScene.fighter == fighter:
return battlePos
assert(false)
return BattlePosition.LEFT_TOP_BACK
func getFighterSceneForFighter(fighter:BattleFighter) -> BattleFighterScene:
for battlePos in fighterMap.keys():
var fighterScene:BattleFighterScene = fighterMap[battlePos]
if fighterScene.fighter == fighter:
return fighterScene
return null
func startBattle(params:Dictionary) -> void:
assert(params.has('fighters'))
assert(!active)
var cutscene:Cutscene = params.get('cutscene', Cutscene.new())
for battlePos in params['fighters'].keys():
var fighterScene:BattleFighterScene = fighterMap.get(battlePos, null)
assert(fighterScene != null)
fighterScene.setFighter(params['fighters'][battlePos])
# Initial cutscene elements. In future I may need to make this editable
# somehow?
cutscene.addCallable({ "function": CutsceneBattleAction.playerDecision })
if !cutscene.running:
cutscene.start()
active = true

View File

@@ -4,21 +4,9 @@
[ext_resource type="Script" uid="uid://dihfp05x6pktn" path="res://battle/BattleScene.gd" id="1_acaen"]
[ext_resource type="PackedScene" uid="uid://ktmvnapibv2q" path="res://battle/ui/ActionBox.tscn" id="2_c3ndu"]
[node name="BattleScene" type="Node3D" node_paths=PackedStringArray("actionBox", "fighterTopLeftBack", "fighterTopLeftFront", "fighterMiddleLeftBack", "fighterMiddleLeftFront", "fighterBottomLeftBack", "fighterBottomLeftFront", "fighterTopRightBack", "fighterTopRightFront", "fighterMiddleRightBack", "fighterMiddleRightFront", "fighterBottomRightBack", "fighterBottomRightFront")]
[node name="BattleScene" type="Node3D" node_paths=PackedStringArray("actionBox")]
script = ExtResource("1_acaen")
actionBox = NodePath("UI/ActionBox")
fighterTopLeftBack = NodePath("Fighters/LeftTopBack")
fighterTopLeftFront = NodePath("Fighters/LeftTopFront")
fighterMiddleLeftBack = NodePath("Fighters/LeftMiddleBack")
fighterMiddleLeftFront = NodePath("Fighters/LeftMiddleFront")
fighterBottomLeftBack = NodePath("Fighters/LeftBottomBack")
fighterBottomLeftFront = NodePath("Fighters/LeftBottomFront")
fighterTopRightBack = NodePath("Fighters/RightTopBack")
fighterTopRightFront = NodePath("Fighters/RightTopFront")
fighterMiddleRightBack = NodePath("Fighters/RightMiddleBack")
fighterMiddleRightFront = NodePath("Fighters/RightMiddleFront")
fighterBottomRightBack = NodePath("Fighters/RightBottomBack")
fighterBottomRightFront = NodePath("Fighters/RightBottomFront")
metadata/_custom_type_script = "uid://dihfp05x6pktn"
[node name="UI" type="Control" parent="."]
@@ -42,39 +30,50 @@ text = "Battle"
[node name="LeftTopBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 3, 0)
battlePosition = 0
[node name="LeftTopFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 3, 0)
battlePosition = 1
[node name="LeftMiddleBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 0, 0)
battlePosition = 2
[node name="LeftMiddleFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.754, 0, 0)
[node name="LeftBottomBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, -3, 0)
battlePosition = 4
[node name="LeftBottomFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, -3, 0)
battlePosition = 5
[node name="RightTopFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 3, 0)
battlePosition = 7
[node name="RightTopBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 3, 0)
battlePosition = 6
[node name="RightMiddleFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0)
battlePosition = 9
[node name="RightMiddleBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, 0)
battlePosition = 8
[node name="RightBottomFront" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, -3, 0)
battlePosition = 11
[node name="RightBottomBack" parent="Fighters" instance=ExtResource("1_abr1f")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, -3, 0)
battlePosition = 10
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 6.9021)

View File

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

View File

@@ -0,0 +1,14 @@
class_name BattleAction
const BattleFighter = preload("res://battle/fighter/BattleFighter.gd")
static func playerDecisionCallable(_params:Dictionary) -> int:
BATTLE.battleScene.actionBox.visible = true
var move = await BATTLE.battleScene.actionBox.decisionMade
BATTLE.battleScene.actionBox.visible = false
return Cutscene.CUTSCENE_CONTINUE
static func getPlayerDecisionCallable(fighter:BattleFighter) -> Dictionary:
return {
"function": playerDecisionCallable,
"fighter": fighter
}

View File

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

View File

@@ -5,40 +5,72 @@ enum Status {
DEAD,
}
enum FighterTeam {
PLAYER,
ENEMY
}
enum FighterController {
PLAYER,
AI
}
# Health
var health:int
var maxHealth:int
var mp:int
var maxMp:int
var status:Status = Status.NORMAL
var status:Status
var attack:int = 10
var defense:int = 5
var speed:int = 5
var magic:int = 5
var luck:int = 1
# Identity
var team:FighterTeam
var controller:FighterController
func _init(
maxHealth:int = 100,
maxMp:int = 50,
) -> void:
self.maxHealth = maxHealth
self.health = maxHealth
self.maxMp = maxMp
self.mp = maxMp
# Stats
var attack:int
var defense:int
var speed:int
var magic:int
var luck:int
# Equipment
# Signals
signal healthChanged(difference:int)
signal mpChanged(difference:int)
signal statusChanged(oldStatus:Status, newStatus:Status)
func _init(params:Dictionary) -> void:
self.maxHealth = params.get('max_health', 100)
self.maxMp = params.get('max_mp', 50)
self.attack = params.get('attack', 10)
self.defense = params.get('defense', 5)
self.speed = params.get('speed', 5)
self.magic = params.get('magic', 5)
self.luck = params.get('luck', 1)
self.team = params.get('team', FighterTeam.ENEMY)
self.controller = params.get('controller', FighterController.PLAYER)
self.health = self.maxHealth
self.mp = self.maxMp
func damage(amount:int) -> void:
assert(amount > 0)
if status == Status.DEAD:
return
health = max(health - amount, 0)
healthChanged.emit(-amount)
if health == 0:
var oldStatus = status
status = Status.DEAD
statusChanged.emit(oldStatus, status)
func heal(amount:int) -> void:
assert(amount > 0)
if status == Status.DEAD:
return
health = min(health + amount, maxHealth)
healthChanged.emit(amount)
func revive(health:int) -> void:
assert(health > 0)
@@ -47,14 +79,18 @@ func revive(health:int) -> void:
health = min(health, maxHealth)
status = Status.NORMAL
self.health = health
statusChanged.emit(Status.DEAD, Status.NORMAL)
healthChanged.emit(health)
func mpConsume(amount:int) -> void:
assert(amount > 0)
mp = max(mp - amount, 0)
mpChanged.emit(-amount)
func mpRestore(amount:int) -> void:
assert(amount > 0)
mp = min(mp + amount, maxMp)
mpChanged.emit(amount)
func isCrit() -> bool:
# 10% chance of a crit

View File

@@ -1,15 +1,26 @@
class_name BattleFighterScene extends Node3D
var fighter:BattleFighter
@export var battlePosition:BattleSingleton.BattlePosition = BattleSingleton.BattlePosition.LEFT_MIDDLE_FRONT
func _ready() -> void:
self.visible = false
if fighter:
setFighter(fighter)
func _getFighter() -> BattleFighter:
return BATTLE.getFighterAtPosition(self.battlePosition)
func _updateFighter() -> void:
var fighter = _getFighter()
if fighter == null:
self.visible = false
return
func setFighter(fighter:BattleFighter) -> void:
print("Setting fighter: %s" % fighter)
# Set up the visual representation of the fighter here
self.fighter = fighter
self.visible = true
pass
func _enter_tree() -> void:
BATTLE.battleFightersChanged.connect(onFightersChanged)
self._updateFighter()
func _exit_tree() -> void:
BATTLE.battleFightersChanged.disconnect(onFightersChanged)
func onFightersChanged() -> void:
_updateFighter()

View File

@@ -1,6 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://d1xyb0hdf1yeh"]
[gd_scene load_steps=5 format=3 uid="uid://d1xyb0hdf1yeh"]
[ext_resource type="Script" uid="uid://bgycdhsouwhwt" path="res://battle/fighter/BattleFighterScene.gd" id="1_veb1i"]
[ext_resource type="SpriteFrames" uid="uid://cqqkm34a46ri6" path="res://battle/fighter/idk/green_dragon_frames.tres" id="2_e55p4"]
[sub_resource type="BoxMesh" id="BoxMesh_veb1i"]
@@ -12,5 +13,11 @@ script = ExtResource("1_veb1i")
metadata/_custom_type_script = "uid://bgycdhsouwhwt"
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
visible = false
mesh = SubResource("BoxMesh_veb1i")
surface_material_override/0 = SubResource("StandardMaterial3D_e55p4")
[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="."]
sprite_frames = ExtResource("2_e55p4")
animation = &"idle"
frame_progress = 0.746159

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,35 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ivi4wtsktmns"
path.s3tc="res://.godot/imported/DAGRONS5.png-68b2402a87bd4c48daaac1f8405a1e4d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://battle/fighter/idk/DAGRONS5.png"
dest_files=["res://.godot/imported/DAGRONS5.png-68b2402a87bd4c48daaac1f8405a1e4d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@@ -0,0 +1,7 @@
[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cucnk4a46odta"]
[ext_resource type="Texture2D" uid="uid://ivi4wtsktmns" path="res://battle/fighter/idk/DAGRONS5.png" id="1_s00hx"]
[resource]
atlas = ExtResource("1_s00hx")
region = Rect2(16, 45.6621, 66, 83.3379)

View File

@@ -0,0 +1,19 @@
[gd_resource type="SpriteFrames" load_steps=2 format=3 uid="uid://cqqkm34a46ri6"]
[ext_resource type="Texture2D" uid="uid://cucnk4a46odta" path="res://battle/fighter/idk/green_dragon.tres" id="1_vtgsa"]
[resource]
animations = [{
"frames": [],
"loop": true,
"name": &"attack",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": ExtResource("1_vtgsa")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}]