Appearance sets

This commit is contained in:
gamer147
2026-04-09 07:58:58 -04:00
parent b807e9897d
commit 6b46d1c274
23 changed files with 445 additions and 81 deletions

BIN
assets/sprites/CP002AB.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b6smsdyydtiv4"
path="res://.godot/imported/CP002AB.BMP-83c77e61ea705a94bd90d268ad08d826.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/sprites/CP002AB.BMP"
dest_files=["res://.godot/imported/CP002AB.BMP-83c77e61ea705a94bd90d268ad08d826.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
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=1

71
export_presets.cfg Normal file
View File

@@ -0,0 +1,71 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
patches=PackedStringArray()
patch_delta_encoding=false
patch_delta_compression_level_zstd=19
patch_delta_min_reduction=0.1
patch_delta_include_filters="*"
patch_delta_exclude_filters=""
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
shader_baker/enabled=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name=""
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"

View File

@@ -3,8 +3,6 @@
[ext_resource type="Script" uid="uid://cmh4lphvboggy" path="res://scripts/battle/deployed_units/deployed_unit.gd" id="1_cq4v0"] [ext_resource type="Script" uid="uid://cmh4lphvboggy" path="res://scripts/battle/deployed_units/deployed_unit.gd" id="1_cq4v0"]
[ext_resource type="Texture2D" uid="uid://cw5su6lignryo" path="res://assets/sprites/flag.png" id="2_fhs1y"] [ext_resource type="Texture2D" uid="uid://cw5su6lignryo" path="res://assets/sprites/flag.png" id="2_fhs1y"]
[ext_resource type="Shader" uid="uid://bd8ki8xwym5nc" path="res://shaders/chroma_key.gdshader" id="3_fhs1y"] [ext_resource type="Shader" uid="uid://bd8ki8xwym5nc" path="res://shaders/chroma_key.gdshader" id="3_fhs1y"]
[ext_resource type="Texture2D" uid="uid://dyutp4m5d53gd" path="res://assets/sprites/CP002AA.BMP" id="3_on614"]
[sub_resource type="GDScript" id="GDScript_on614"] [sub_resource type="GDScript" id="GDScript_on614"]
resource_name = "UnitSelectorHandler" resource_name = "UnitSelectorHandler"
script/source = "extends ColorRect script/source = "extends ColorRect
@@ -27,42 +25,6 @@ shader = ExtResource("3_fhs1y")
shader_parameter/key_color = Color(0, 1, 0, 1) shader_parameter/key_color = Color(0, 1, 0, 1)
shader_parameter/threshold = 0.01 shader_parameter/threshold = 0.01
[sub_resource type="AtlasTexture" id="AtlasTexture_fhs1y"]
atlas = ExtResource("3_on614")
region = Rect2(0, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_4j20j"]
atlas = ExtResource("3_on614")
region = Rect2(40, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_v0xod"]
atlas = ExtResource("3_on614")
region = Rect2(0, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_50p1h"]
atlas = ExtResource("3_on614")
region = Rect2(40, 50, 40, 50)
[sub_resource type="SpriteFrames" id="SpriteFrames_7jqdg"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_fhs1y")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4j20j")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_v0xod")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_50p1h")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}]
[node name="DeployedUnit" type="Node2D" unique_id=1893234933 groups=["deployed_units"]] [node name="DeployedUnit" type="Node2D" unique_id=1893234933 groups=["deployed_units"]]
script = ExtResource("1_cq4v0") script = ExtResource("1_cq4v0")
metadata/_custom_type_script = "uid://cmh4lphvboggy" metadata/_custom_type_script = "uid://cmh4lphvboggy"
@@ -83,9 +45,6 @@ script = SubResource("GDScript_fhs1y")
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1796991032] [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1796991032]
material = SubResource("ShaderMaterial_fhs1y") material = SubResource("ShaderMaterial_fhs1y")
position = Vector2(50, 50) position = Vector2(50, 50)
sprite_frames = SubResource("SpriteFrames_7jqdg")
animation = &"idle"
autoplay = "idle"
[connection signal="unit_allegiance_changed" from="." to="AllegianceIndicator" method="_on_unit_unit_allegiance_changed"] [connection signal="unit_allegiance_changed" from="." to="AllegianceIndicator" method="_on_unit_unit_allegiance_changed"]
[connection signal="unit_selected_changed" from="." to="SelectionIndicator" method="_unit_selected_changed"] [connection signal="unit_selected_changed" from="." to="SelectionIndicator" method="_unit_selected_changed"]

View File

@@ -0,0 +1,178 @@
[gd_resource type="Resource" script_class="UnitAppearanceSet" format=3 uid="uid://c18djmm6orf5y"]
[ext_resource type="Script" uid="uid://divxkbo321ql" path="res://scripts/units/unit_appearance_set.gd" id="1_am7go"]
[ext_resource type="Texture2D" uid="uid://b6smsdyydtiv4" path="res://assets/sprites/CP002AB.BMP" id="1_cdqv0"]
[ext_resource type="Texture2D" uid="uid://dyutp4m5d53gd" path="res://assets/sprites/CP002AA.BMP" id="2_3pgcd"]
[sub_resource type="AtlasTexture" id="AtlasTexture_4hgk0"]
atlas = ExtResource("1_cdqv0")
region = Rect2(0, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_scnul"]
atlas = ExtResource("1_cdqv0")
region = Rect2(40, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_ec51f"]
atlas = ExtResource("1_cdqv0")
region = Rect2(80, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_ix7mx"]
atlas = ExtResource("1_cdqv0")
region = Rect2(120, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_su6vo"]
atlas = ExtResource("2_3pgcd")
region = Rect2(0, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_6idlb"]
atlas = ExtResource("2_3pgcd")
region = Rect2(40, 0, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_ui8f1"]
atlas = ExtResource("2_3pgcd")
region = Rect2(0, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_wk1hp"]
atlas = ExtResource("2_3pgcd")
region = Rect2(40, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_p4e4i"]
atlas = ExtResource("1_cdqv0")
region = Rect2(0, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_knbtp"]
atlas = ExtResource("1_cdqv0")
region = Rect2(40, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_ni45v"]
atlas = ExtResource("1_cdqv0")
region = Rect2(80, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_a51r0"]
atlas = ExtResource("1_cdqv0")
region = Rect2(120, 50, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_pvxdl"]
atlas = ExtResource("1_cdqv0")
region = Rect2(0, 150, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_qle0x"]
atlas = ExtResource("1_cdqv0")
region = Rect2(40, 150, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_iork5"]
atlas = ExtResource("1_cdqv0")
region = Rect2(80, 150, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_hbqxy"]
atlas = ExtResource("1_cdqv0")
region = Rect2(120, 150, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_e4j68"]
atlas = ExtResource("1_cdqv0")
region = Rect2(0, 100, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_n1qde"]
atlas = ExtResource("1_cdqv0")
region = Rect2(40, 100, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_de2lv"]
atlas = ExtResource("1_cdqv0")
region = Rect2(80, 100, 40, 50)
[sub_resource type="AtlasTexture" id="AtlasTexture_1nls0"]
atlas = ExtResource("1_cdqv0")
region = Rect2(120, 100, 40, 50)
[sub_resource type="SpriteFrames" id="SpriteFrames_psufo"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_4hgk0")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_scnul")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ec51f")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ix7mx")
}],
"loop": true,
"name": &"down",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_su6vo")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_6idlb")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ui8f1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_wk1hp")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_p4e4i")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_knbtp")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ni45v")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_a51r0")
}],
"loop": true,
"name": &"left",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_pvxdl")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qle0x")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_iork5")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_hbqxy")
}],
"loop": true,
"name": &"right",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_e4j68")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_n1qde")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_de2lv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1nls0")
}],
"loop": true,
"name": &"up",
"speed": 8.0
}]
[resource]
script = ExtResource("1_am7go")
deployed_sprite_sheet = SubResource("SpriteFrames_psufo")
metadata/_custom_type_script = "uid://divxkbo321ql"

View File

@@ -0,0 +1,33 @@
[gd_resource type="Resource" script_class="Unit" format=3 uid="uid://sqrlba15ncyr"]
[ext_resource type="Script" uid="uid://c016mxgatcpse" path="res://scripts/units/unit.gd" id="1_bqd3m"]
[ext_resource type="Script" uid="uid://divxkbo321ql" path="res://scripts/units/unit_appearance_set.gd" id="1_lko56"]
[ext_resource type="Script" uid="uid://b67rtbb5gixus" path="res://scripts/battle/combat_tactics/combat_tactic.gd" id="2_0tmvt"]
[ext_resource type="Resource" uid="uid://c18djmm6orf5y" path="res://resources/units/appearance_sets/lily_child_deployed.tres" id="2_f8ij3"]
[ext_resource type="Script" uid="uid://b402hsmbaj536" path="res://scripts/units/unit_appearance.gd" id="2_nxnrh"]
[ext_resource type="Script" uid="uid://d37ulss2k0bq5" path="res://scripts/units/unit_info.gd" id="3_f8ij3"]
[ext_resource type="Script" uid="uid://cydoey8a8nmb8" path="res://scripts/units/unit_stats.gd" id="5_rqhbp"]
[sub_resource type="Resource" id="Resource_ki4ax"]
script = ExtResource("2_nxnrh")
appearance_sets = Dictionary[String, ExtResource("1_lko56")]({
"default": ExtResource("2_f8ij3")
})
metadata/_custom_type_script = "uid://b402hsmbaj536"
[sub_resource type="Resource" id="Resource_q2jxx"]
script = ExtResource("3_f8ij3")
name = "Lily"
metadata/_custom_type_script = "uid://d37ulss2k0bq5"
[sub_resource type="Resource" id="Resource_nc6h6"]
script = ExtResource("5_rqhbp")
max_hp = 20
metadata/_custom_type_script = "uid://cydoey8a8nmb8"
[resource]
script = ExtResource("1_bqd3m")
stats = SubResource("Resource_nc6h6")
info = SubResource("Resource_q2jxx")
appearance = SubResource("Resource_ki4ax")
metadata/_custom_type_script = "uid://c016mxgatcpse"

View File

@@ -78,23 +78,18 @@ script/source = "extends TextureButton
const COMBAT_SCENE = preload(\"res://scenes/views/battle_view.tscn\") const COMBAT_SCENE = preload(\"res://scenes/views/battle_view.tscn\")
const PLAYER_ALLEGIANCE = preload(\"res://resources/allegiance_types/player_allegiance.tres\") const PLAYER_ALLEGIANCE = preload(\"res://resources/allegiance_types/player_allegiance.tres\")
const ENEMY_ALLEGIANCE = preload(\"res://resources/allegiance_types/enemy_allegiance.tres\") const ENEMY_ALLEGIANCE = preload(\"res://resources/allegiance_types/enemy_allegiance.tres\")
const LILY_CHILD = preload(\"res://resources/units/lily_child.tres\")
func _pressed() -> void: func _pressed() -> void:
await get_tree().create_timer(0.2).timeout await get_tree().create_timer(0.2).timeout
var combat_instance := COMBAT_SCENE.instantiate() var combat_instance := COMBAT_SCENE.instantiate()
var combat_map: CombatMap = combat_instance.find_child(\"CombatMap\") var combat_map: CombatMap = combat_instance.find_child(\"CombatMap\")
var player_unit := Unit.new() var player_unit: Unit = LILY_CHILD.duplicate(true)
player_unit.stats = UnitStats.new()
player_unit.info = UnitInfo.new()
player_unit.info.name = \"Putit\"
player_unit.allegiance = PLAYER_ALLEGIANCE player_unit.allegiance = PLAYER_ALLEGIANCE
combat_map.deploy_unit(player_unit, Vector2i(3, 3)) combat_map.deploy_unit(player_unit, Vector2i(3, 3))
var enemy_unit := Unit.new() var enemy_unit: Unit = LILY_CHILD.duplicate(true)
enemy_unit.stats = UnitStats.new()
enemy_unit.info = UnitInfo.new()
enemy_unit.info.name = \"Putit\"
enemy_unit.allegiance = ENEMY_ALLEGIANCE enemy_unit.allegiance = ENEMY_ALLEGIANCE
combat_map.deploy_unit(enemy_unit, Vector2i(6, 3)) combat_map.deploy_unit(enemy_unit, Vector2i(6, 3))

View File

@@ -22,7 +22,7 @@ func create_proposal(attacker: DeployedUnit, defender: DeployedUnit, distance: i
func _filter_tactics(deployed: DeployedUnit, distance: int) -> Array[CombatTactic]: func _filter_tactics(deployed: DeployedUnit, distance: int) -> Array[CombatTactic]:
var valid: Array[CombatTactic] = [] var valid: Array[CombatTactic] = []
for tactic in deployed.tactics: for tactic in deployed.tactics:
if tactic.tactic_range and tactic.tactic_range.is_valid_range(distance, deployed.unit): if tactic.tactic_range and tactic.tactic_range.is_valid_range(distance, deployed.current_stats):
valid.append(tactic) valid.append(tactic)
return valid return valid
@@ -35,27 +35,29 @@ func _find_default_attack(tactics: Array[CombatTactic]) -> CombatTactic:
func _snapshot(deployed: DeployedUnit, opponent: DeployedUnit, available: Array[CombatTactic], selected: CombatTactic, opponent_selected: CombatTactic) -> CombatProposal.CombatantStats: func _snapshot(deployed: DeployedUnit, opponent: DeployedUnit, available: Array[CombatTactic], selected: CombatTactic, opponent_selected: CombatTactic) -> CombatProposal.CombatantStats:
var current := deployed.current_stats
var opp_current := opponent.current_stats
var stats := CombatProposal.CombatantStats.new() var stats := CombatProposal.CombatantStats.new()
stats.deployed = deployed stats.deployed = deployed
stats.max_hp = deployed.unit.stats.max_hp stats.max_hp = current.max_hp
stats.hp = deployed.current_stats.current_hp stats.hp = current.current_hp
stats.sp = deployed.current_stats.current_sp stats.sp = current.current_sp
stats.spd = deployed.unit.stats.spd stats.spd = current.spd
stats.available_tactics = available stats.available_tactics = available
stats.selected_tactic = selected stats.selected_tactic = selected
if selected and selected.deals_damage(): if selected and selected.deals_damage():
var offensive: Dictionary = selected.get_offensive_stats(deployed.unit) var offensive: Dictionary = selected.get_offensive_stats(current)
stats.atk = offensive["atk"] stats.atk = offensive["atk"]
stats.hit = offensive["hit"] - opponent.unit.stats.eva stats.hit = offensive["hit"] - opp_current.eva
else: else:
stats.atk = 0 stats.atk = 0
stats.hit = 0 stats.hit = 0
if opponent_selected and opponent_selected.deals_damage(): if opponent_selected and opponent_selected.deals_damage():
stats.def = opponent_selected.get_relevant_defense(deployed.unit) stats.def = opponent_selected.get_relevant_defense(current)
else: else:
stats.def = deployed.unit.stats.phys_def stats.def = current.phys_def
return stats return stats
@@ -74,18 +76,18 @@ func update_tactic(proposal: CombatProposal, is_attacker: bool, tactic: CombatTa
# Recalculate this side's offensive stats # Recalculate this side's offensive stats
if tactic and tactic.deals_damage(): if tactic and tactic.deals_damage():
var offensive: Dictionary = tactic.get_offensive_stats(self_stats.deployed.unit) var offensive: Dictionary = tactic.get_offensive_stats(self_stats.deployed.current_stats)
self_stats.atk = offensive["atk"] self_stats.atk = offensive["atk"]
self_stats.hit = offensive["hit"] - opp_stats.deployed.unit.stats.eva self_stats.hit = offensive["hit"] - opp_stats.deployed.current_stats.eva
else: else:
self_stats.atk = 0 self_stats.atk = 0
self_stats.hit = 0 self_stats.hit = 0
# Recalculate opponent's def based on this side's new tactic # Recalculate opponent's def based on this side's new tactic
if tactic and tactic.deals_damage(): if tactic and tactic.deals_damage():
opp_stats.def = tactic.get_relevant_defense(opp_stats.deployed.unit) opp_stats.def = tactic.get_relevant_defense(opp_stats.deployed.current_stats)
else: else:
opp_stats.def = opp_stats.deployed.unit.stats.phys_def opp_stats.def = opp_stats.deployed.current_stats.phys_def
func select_ai_tactic(deployed: DeployedUnit, opponent: DeployedUnit, available_tactics: Array[CombatTactic]) -> CombatTactic: func select_ai_tactic(deployed: DeployedUnit, opponent: DeployedUnit, available_tactics: Array[CombatTactic]) -> CombatTactic:
@@ -95,8 +97,8 @@ func select_ai_tactic(deployed: DeployedUnit, opponent: DeployedUnit, available_
for tactic in available_tactics: for tactic in available_tactics:
if not tactic.deals_damage(): if not tactic.deals_damage():
continue continue
var offensive: Dictionary = tactic.get_offensive_stats(deployed.unit) var offensive: Dictionary = tactic.get_offensive_stats(deployed.current_stats)
var defense: int = tactic.get_relevant_defense(opponent.unit) var defense: int = tactic.get_relevant_defense(opponent.current_stats)
var damage := maxi(offensive["atk"] - defense, 0) var damage := maxi(offensive["atk"] - defense, 0)
if damage > best_damage: if damage > best_damage:
best_damage = damage best_damage = damage

View File

@@ -3,11 +3,11 @@ class_name CombatTactic extends Resource
@export var tactic_name: String = "" @export var tactic_name: String = ""
@export var tactic_range: CombatTacticRange @export var tactic_range: CombatTacticRange
func get_offensive_stats(_unit: Unit) -> Variant: func get_offensive_stats(_stats: DeployedUnitStats) -> Variant:
return null return null
func get_relevant_defense(unit: Unit) -> int: func get_relevant_defense(stats: DeployedUnitStats) -> int:
return unit.stats.phys_def return stats.phys_def
func deals_damage() -> bool: func deals_damage() -> bool:
return false return false

View File

@@ -1,5 +1,5 @@
# resources/resource_definitions/any_combat_tactic_range.gd # resources/resource_definitions/any_combat_tactic_range.gd
class_name AnyCombatTacticRange extends CombatTacticRange class_name AnyCombatTacticRange extends CombatTacticRange
func is_valid_range(_distance: int, _unit: Unit) -> bool: func is_valid_range(_distance: int, _stats: DeployedUnitStats) -> bool:
return true return true

View File

@@ -1,5 +1,5 @@
# resources/resource_definitions/combat_tactic_range.gd # resources/resource_definitions/combat_tactic_range.gd
class_name CombatTacticRange extends Resource class_name CombatTacticRange extends Resource
func is_valid_range(_distance: int, _unit: Unit) -> bool: func is_valid_range(_distance: int, _stats: DeployedUnitStats) -> bool:
return false return false

View File

@@ -3,5 +3,5 @@ class_name FixedCombatTacticRange extends CombatTacticRange
@export var tactic_range: int = 1 @export var tactic_range: int = 1
func is_valid_range(distance: int, unit: Unit) -> bool: func is_valid_range(distance: int, _stats: DeployedUnitStats) -> bool:
return distance <= tactic_range return distance <= tactic_range

View File

@@ -1,5 +1,5 @@
# resources/resource_definitions/unit_matching_combat_tactic_range.gd # resources/resource_definitions/unit_matching_combat_tactic_range.gd
class_name UnitMatchingCombatTacticRange extends CombatTacticRange class_name UnitMatchingCombatTacticRange extends CombatTacticRange
func is_valid_range(distance: int, unit: Unit) -> bool: func is_valid_range(distance: int, stats: DeployedUnitStats) -> bool:
return distance <= unit.stats.atk_range return distance <= stats.atk_range

View File

@@ -1,10 +1,10 @@
class_name AttackCombatTactic extends CombatTactic class_name AttackCombatTactic extends CombatTactic
func get_offensive_stats(unit: Unit) -> Variant: func get_offensive_stats(stats: DeployedUnitStats) -> Variant:
return {"atk": unit.stats.phys_atk, "hit": unit.stats.hit} return {"atk": stats.phys_atk, "hit": stats.hit}
func get_relevant_defense(unit: Unit) -> int: func get_relevant_defense(stats: DeployedUnitStats) -> int:
return unit.stats.phys_def return stats.phys_def
func deals_damage() -> bool: func deals_damage() -> bool:
return true return true

View File

@@ -1,10 +1,10 @@
class_name DefendCombatTactic extends CombatTactic class_name DefendCombatTactic extends CombatTactic
func get_offensive_stats(_unit: Unit) -> Variant: func get_offensive_stats(_stats: DeployedUnitStats) -> Variant:
return null return null
func get_relevant_defense(unit: Unit) -> int: func get_relevant_defense(stats: DeployedUnitStats) -> int:
return unit.stats.phys_def return stats.phys_def
func deals_damage() -> bool: func deals_damage() -> bool:
return false return false

View File

@@ -59,7 +59,7 @@ func _on_unit_died(deployed: DeployedUnit) -> void:
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
if _selected_unit and is_instance_valid(_selected_unit): if _selected_unit and is_instance_valid(_selected_unit):
hp_bar.max_value = _selected_unit.unit.stats.max_hp hp_bar.max_value = _selected_unit.current_stats.max_hp
hp_bar.value = _selected_unit.current_stats.current_hp hp_bar.value = _selected_unit.current_stats.current_hp
func _unhandled_input(event: InputEvent) -> void: func _unhandled_input(event: InputEvent) -> void:
@@ -72,7 +72,7 @@ func _on_unit_selected_changed(deployed: DeployedUnit, selected: bool) -> void:
if selected: if selected:
_selected_unit = deployed _selected_unit = deployed
name_label.text = deployed.unit.info.name name_label.text = deployed.unit.info.name
hp_bar.max_value = deployed.unit.stats.max_hp hp_bar.max_value = deployed.current_stats.max_hp
hp_bar.value = deployed.current_stats.current_hp hp_bar.value = deployed.current_stats.current_hp
unit_panel.visible = true unit_panel.visible = true
else: else:

View File

@@ -8,6 +8,9 @@ var current_stats: DeployedUnitStats
var tactics: Array[CombatTactic] = [] var tactics: Array[CombatTactic] = []
var state: UnitState = UnitState.ALIVE var state: UnitState = UnitState.ALIVE
var _sprite: AnimatedSprite2D
var _previous_position: Vector2
signal unit_selected_changed(deployed: DeployedUnit, selected: bool) signal unit_selected_changed(deployed: DeployedUnit, selected: bool)
signal unit_allegiance_changed(deployed: DeployedUnit, allegiance: UnitAllegiance) signal unit_allegiance_changed(deployed: DeployedUnit, allegiance: UnitAllegiance)
signal unit_died(deployed: DeployedUnit) signal unit_died(deployed: DeployedUnit)
@@ -17,6 +20,35 @@ func _ready() -> void:
tactics = unit.tactics.duplicate() tactics = unit.tactics.duplicate()
_append_builtin_tactics() _append_builtin_tactics()
unit_allegiance_changed.emit(self, unit.allegiance) unit_allegiance_changed.emit(self, unit.allegiance)
_previous_position = position
_setup_appearance()
func _setup_appearance() -> void:
_sprite = get_node_or_null("AnimatedSprite2D") as AnimatedSprite2D
if not _sprite:
return
var sprite_frames: SpriteFrames = unit.appearance.deployed_sprite_sheet if unit.appearance else null
if not sprite_frames:
return
_sprite.sprite_frames = sprite_frames
_sprite.play("idle")
func _physics_process(_delta: float) -> void:
if not _sprite or not _sprite.sprite_frames:
return
var delta_pos := position - _previous_position
_previous_position = position
if delta_pos.length_squared() < 0.01:
if _sprite.animation != &"idle":
_sprite.play("idle")
return
var anim: StringName
if absf(delta_pos.x) >= absf(delta_pos.y):
anim = &"right" if delta_pos.x > 0 else &"left"
else:
anim = &"down" if delta_pos.y > 0 else &"up"
if _sprite.animation != anim:
_sprite.play(anim)
func _append_builtin_tactics() -> void: func _append_builtin_tactics() -> void:
var attack := AttackCombatTactic.new() var attack := AttackCombatTactic.new()

View File

@@ -5,6 +5,35 @@ class_name DeployedUnitStats extends Resource
@export var current_sp: int @export var current_sp: int
@export var current_fs: int @export var current_fs: int
# Passthrough accessors. Future buff/debuff layers can override these
# without mutating the underlying UnitStats template.
var max_hp: int:
get: return unit_stats.max_hp
var max_sp: int:
get: return unit_stats.max_sp
var max_fs: int:
get: return unit_stats.max_fs
var phys_atk: int:
get: return unit_stats.phys_atk
var phys_def: int:
get: return unit_stats.phys_def
var magic_atk: int:
get: return unit_stats.magic_atk
var magic_def: int:
get: return unit_stats.magic_def
var hit: int:
get: return unit_stats.hit
var atk_range: int:
get: return unit_stats.atk_range
var spd: int:
get: return unit_stats.spd
var eva: int:
get: return unit_stats.eva
var lck: int:
get: return unit_stats.lck
var mov: int:
get: return unit_stats.mov
static func from_unit_stats(source: UnitStats) -> DeployedUnitStats: static func from_unit_stats(source: UnitStats) -> DeployedUnitStats:
var stats := DeployedUnitStats.new() var stats := DeployedUnitStats.new()
stats.unit_stats = source stats.unit_stats = source

View File

@@ -4,3 +4,4 @@ class_name Unit extends Resource
@export var info: UnitInfo @export var info: UnitInfo
@export var allegiance: UnitAllegiance @export var allegiance: UnitAllegiance
@export var tactics: Array[CombatTactic] = [] @export var tactics: Array[CombatTactic] = []
@export var appearance: UnitAppearance

View File

@@ -0,0 +1,19 @@
class_name UnitAppearance extends Resource
@export var default_appearance_key: String = "default"
@export var current_appearance_key: String
@export var appearance_sets: Dictionary[String, UnitAppearanceSet]
var deployed_sprite_sheet: SpriteFrames:
get:
var key: String = current_appearance_key
if(key == null or key == ""):
key = default_appearance_key
if(!appearance_sets.has(key)):
return null
var appearance_set: UnitAppearanceSet = appearance_sets[key]
var sprite_value = appearance_set.deployed_sprite_sheet
if(sprite_value == null):
sprite_value = appearance_sets[default_appearance_key].deployed_sprite_sheet
return sprite_value

View File

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

View File

@@ -0,0 +1,3 @@
class_name UnitAppearanceSet extends Resource
@export var deployed_sprite_sheet: SpriteFrames

View File

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