diff --git a/assets/sprites/CP002AB.BMP b/assets/sprites/CP002AB.BMP new file mode 100644 index 0000000..bb812a4 Binary files /dev/null and b/assets/sprites/CP002AB.BMP differ diff --git a/assets/sprites/CP002AB.BMP.import b/assets/sprites/CP002AB.BMP.import new file mode 100644 index 0000000..2a46ab0 --- /dev/null +++ b/assets/sprites/CP002AB.BMP.import @@ -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 diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..e66d104 --- /dev/null +++ b/export_presets.cfg @@ -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}'" diff --git a/prefabs/deployed_unit.tscn b/prefabs/deployed_unit.tscn index 4f67ee2..1677f5d 100644 --- a/prefabs/deployed_unit.tscn +++ b/prefabs/deployed_unit.tscn @@ -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="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="Texture2D" uid="uid://dyutp4m5d53gd" path="res://assets/sprites/CP002AA.BMP" id="3_on614"] - [sub_resource type="GDScript" id="GDScript_on614"] resource_name = "UnitSelectorHandler" script/source = "extends ColorRect @@ -27,42 +25,6 @@ shader = ExtResource("3_fhs1y") shader_parameter/key_color = Color(0, 1, 0, 1) 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"]] script = ExtResource("1_cq4v0") metadata/_custom_type_script = "uid://cmh4lphvboggy" @@ -83,9 +45,6 @@ script = SubResource("GDScript_fhs1y") [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1796991032] material = SubResource("ShaderMaterial_fhs1y") 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_selected_changed" from="." to="SelectionIndicator" method="_unit_selected_changed"] diff --git a/resources/units/appearance_sets/lily_child_deployed.tres b/resources/units/appearance_sets/lily_child_deployed.tres new file mode 100644 index 0000000..a6068a9 --- /dev/null +++ b/resources/units/appearance_sets/lily_child_deployed.tres @@ -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" diff --git a/resources/units/lily_child.tres b/resources/units/lily_child.tres new file mode 100644 index 0000000..899882c --- /dev/null +++ b/resources/units/lily_child.tres @@ -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" diff --git a/scenes/views/main_menu_view.tscn b/scenes/views/main_menu_view.tscn index c9b1338..a3a1765 100644 --- a/scenes/views/main_menu_view.tscn +++ b/scenes/views/main_menu_view.tscn @@ -78,23 +78,18 @@ script/source = "extends TextureButton const COMBAT_SCENE = preload(\"res://scenes/views/battle_view.tscn\") const PLAYER_ALLEGIANCE = preload(\"res://resources/allegiance_types/player_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: await get_tree().create_timer(0.2).timeout var combat_instance := COMBAT_SCENE.instantiate() var combat_map: CombatMap = combat_instance.find_child(\"CombatMap\") - var player_unit := Unit.new() - player_unit.stats = UnitStats.new() - player_unit.info = UnitInfo.new() - player_unit.info.name = \"Putit\" + var player_unit: Unit = LILY_CHILD.duplicate(true) player_unit.allegiance = PLAYER_ALLEGIANCE combat_map.deploy_unit(player_unit, Vector2i(3, 3)) - var enemy_unit := Unit.new() - enemy_unit.stats = UnitStats.new() - enemy_unit.info = UnitInfo.new() - enemy_unit.info.name = \"Putit\" + var enemy_unit: Unit = LILY_CHILD.duplicate(true) enemy_unit.allegiance = ENEMY_ALLEGIANCE combat_map.deploy_unit(enemy_unit, Vector2i(6, 3)) diff --git a/scripts/battle/combat_engine/combat_system.gd b/scripts/battle/combat_engine/combat_system.gd index 379a02f..8c1b1de 100644 --- a/scripts/battle/combat_engine/combat_system.gd +++ b/scripts/battle/combat_engine/combat_system.gd @@ -22,7 +22,7 @@ func create_proposal(attacker: DeployedUnit, defender: DeployedUnit, distance: i func _filter_tactics(deployed: DeployedUnit, distance: int) -> Array[CombatTactic]: var valid: Array[CombatTactic] = [] 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) 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: + var current := deployed.current_stats + var opp_current := opponent.current_stats var stats := CombatProposal.CombatantStats.new() stats.deployed = deployed - stats.max_hp = deployed.unit.stats.max_hp - stats.hp = deployed.current_stats.current_hp - stats.sp = deployed.current_stats.current_sp - stats.spd = deployed.unit.stats.spd + stats.max_hp = current.max_hp + stats.hp = current.current_hp + stats.sp = current.current_sp + stats.spd = current.spd stats.available_tactics = available stats.selected_tactic = selected 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.hit = offensive["hit"] - opponent.unit.stats.eva + stats.hit = offensive["hit"] - opp_current.eva else: stats.atk = 0 stats.hit = 0 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: - stats.def = deployed.unit.stats.phys_def + stats.def = current.phys_def return stats @@ -74,18 +76,18 @@ func update_tactic(proposal: CombatProposal, is_attacker: bool, tactic: CombatTa # Recalculate this side's offensive stats 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.hit = offensive["hit"] - opp_stats.deployed.unit.stats.eva + self_stats.hit = offensive["hit"] - opp_stats.deployed.current_stats.eva else: self_stats.atk = 0 self_stats.hit = 0 # Recalculate opponent's def based on this side's new tactic 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: - 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: @@ -95,8 +97,8 @@ func select_ai_tactic(deployed: DeployedUnit, opponent: DeployedUnit, available_ for tactic in available_tactics: if not tactic.deals_damage(): continue - var offensive: Dictionary = tactic.get_offensive_stats(deployed.unit) - var defense: int = tactic.get_relevant_defense(opponent.unit) + var offensive: Dictionary = tactic.get_offensive_stats(deployed.current_stats) + var defense: int = tactic.get_relevant_defense(opponent.current_stats) var damage := maxi(offensive["atk"] - defense, 0) if damage > best_damage: best_damage = damage diff --git a/scripts/battle/combat_tactics/combat_tactic.gd b/scripts/battle/combat_tactics/combat_tactic.gd index 0627085..cc8dca9 100644 --- a/scripts/battle/combat_tactics/combat_tactic.gd +++ b/scripts/battle/combat_tactics/combat_tactic.gd @@ -3,11 +3,11 @@ class_name CombatTactic extends Resource @export var tactic_name: String = "" @export var tactic_range: CombatTacticRange -func get_offensive_stats(_unit: Unit) -> Variant: +func get_offensive_stats(_stats: DeployedUnitStats) -> Variant: return null -func get_relevant_defense(unit: Unit) -> int: - return unit.stats.phys_def +func get_relevant_defense(stats: DeployedUnitStats) -> int: + return stats.phys_def func deals_damage() -> bool: return false diff --git a/scripts/battle/combat_tactics/ranges/any_combat_tactic_range.gd b/scripts/battle/combat_tactics/ranges/any_combat_tactic_range.gd index 9b2e81b..f2f86ad 100644 --- a/scripts/battle/combat_tactics/ranges/any_combat_tactic_range.gd +++ b/scripts/battle/combat_tactics/ranges/any_combat_tactic_range.gd @@ -1,5 +1,5 @@ # resources/resource_definitions/any_combat_tactic_range.gd 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 diff --git a/scripts/battle/combat_tactics/ranges/combat_tactic_range.gd b/scripts/battle/combat_tactics/ranges/combat_tactic_range.gd index 7645ea5..23fa8e2 100644 --- a/scripts/battle/combat_tactics/ranges/combat_tactic_range.gd +++ b/scripts/battle/combat_tactics/ranges/combat_tactic_range.gd @@ -1,5 +1,5 @@ # resources/resource_definitions/combat_tactic_range.gd 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 diff --git a/scripts/battle/combat_tactics/ranges/fixed_combat_tactic_range.gd b/scripts/battle/combat_tactics/ranges/fixed_combat_tactic_range.gd index 0901048..b97ccc8 100644 --- a/scripts/battle/combat_tactics/ranges/fixed_combat_tactic_range.gd +++ b/scripts/battle/combat_tactics/ranges/fixed_combat_tactic_range.gd @@ -3,5 +3,5 @@ class_name FixedCombatTacticRange extends CombatTacticRange @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 diff --git a/scripts/battle/combat_tactics/ranges/unit_matching_combat_tactic_range.gd b/scripts/battle/combat_tactics/ranges/unit_matching_combat_tactic_range.gd index b668e57..dbd7c09 100644 --- a/scripts/battle/combat_tactics/ranges/unit_matching_combat_tactic_range.gd +++ b/scripts/battle/combat_tactics/ranges/unit_matching_combat_tactic_range.gd @@ -1,5 +1,5 @@ # resources/resource_definitions/unit_matching_combat_tactic_range.gd class_name UnitMatchingCombatTacticRange extends CombatTacticRange -func is_valid_range(distance: int, unit: Unit) -> bool: - return distance <= unit.stats.atk_range +func is_valid_range(distance: int, stats: DeployedUnitStats) -> bool: + return distance <= stats.atk_range diff --git a/scripts/battle/combat_tactics/tactics/attack_combat_tactic.gd b/scripts/battle/combat_tactics/tactics/attack_combat_tactic.gd index d3758bc..161fb13 100644 --- a/scripts/battle/combat_tactics/tactics/attack_combat_tactic.gd +++ b/scripts/battle/combat_tactics/tactics/attack_combat_tactic.gd @@ -1,10 +1,10 @@ class_name AttackCombatTactic extends CombatTactic -func get_offensive_stats(unit: Unit) -> Variant: - return {"atk": unit.stats.phys_atk, "hit": unit.stats.hit} +func get_offensive_stats(stats: DeployedUnitStats) -> Variant: + return {"atk": stats.phys_atk, "hit": stats.hit} -func get_relevant_defense(unit: Unit) -> int: - return unit.stats.phys_def +func get_relevant_defense(stats: DeployedUnitStats) -> int: + return stats.phys_def func deals_damage() -> bool: return true diff --git a/scripts/battle/combat_tactics/tactics/defend_combat_tactic.gd b/scripts/battle/combat_tactics/tactics/defend_combat_tactic.gd index 9fc95cb..1f4c7c6 100644 --- a/scripts/battle/combat_tactics/tactics/defend_combat_tactic.gd +++ b/scripts/battle/combat_tactics/tactics/defend_combat_tactic.gd @@ -1,10 +1,10 @@ class_name DefendCombatTactic extends CombatTactic -func get_offensive_stats(_unit: Unit) -> Variant: +func get_offensive_stats(_stats: DeployedUnitStats) -> Variant: return null -func get_relevant_defense(unit: Unit) -> int: - return unit.stats.phys_def +func get_relevant_defense(stats: DeployedUnitStats) -> int: + return stats.phys_def func deals_damage() -> bool: return false diff --git a/scripts/battle/combat_ui.gd b/scripts/battle/combat_ui.gd index 78b211f..fb70e06 100644 --- a/scripts/battle/combat_ui.gd +++ b/scripts/battle/combat_ui.gd @@ -59,7 +59,7 @@ func _on_unit_died(deployed: DeployedUnit) -> void: func _process(_delta: float) -> void: 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 func _unhandled_input(event: InputEvent) -> void: @@ -72,7 +72,7 @@ func _on_unit_selected_changed(deployed: DeployedUnit, selected: bool) -> void: if selected: _selected_unit = deployed 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 unit_panel.visible = true else: diff --git a/scripts/battle/deployed_units/deployed_unit.gd b/scripts/battle/deployed_units/deployed_unit.gd index 36ab0f2..0e59100 100644 --- a/scripts/battle/deployed_units/deployed_unit.gd +++ b/scripts/battle/deployed_units/deployed_unit.gd @@ -8,6 +8,9 @@ var current_stats: DeployedUnitStats var tactics: Array[CombatTactic] = [] var state: UnitState = UnitState.ALIVE +var _sprite: AnimatedSprite2D +var _previous_position: Vector2 + signal unit_selected_changed(deployed: DeployedUnit, selected: bool) signal unit_allegiance_changed(deployed: DeployedUnit, allegiance: UnitAllegiance) signal unit_died(deployed: DeployedUnit) @@ -17,6 +20,35 @@ func _ready() -> void: tactics = unit.tactics.duplicate() _append_builtin_tactics() 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: var attack := AttackCombatTactic.new() diff --git a/scripts/battle/deployed_units/deployed_unit_stats.gd b/scripts/battle/deployed_units/deployed_unit_stats.gd index 40d44e5..5f55fb2 100644 --- a/scripts/battle/deployed_units/deployed_unit_stats.gd +++ b/scripts/battle/deployed_units/deployed_unit_stats.gd @@ -5,6 +5,35 @@ class_name DeployedUnitStats extends Resource @export var current_sp: 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: var stats := DeployedUnitStats.new() stats.unit_stats = source diff --git a/scripts/units/unit.gd b/scripts/units/unit.gd index 87f8e20..8a24114 100644 --- a/scripts/units/unit.gd +++ b/scripts/units/unit.gd @@ -4,3 +4,4 @@ class_name Unit extends Resource @export var info: UnitInfo @export var allegiance: UnitAllegiance @export var tactics: Array[CombatTactic] = [] +@export var appearance: UnitAppearance diff --git a/scripts/units/unit_appearance.gd b/scripts/units/unit_appearance.gd new file mode 100644 index 0000000..ed852e6 --- /dev/null +++ b/scripts/units/unit_appearance.gd @@ -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 diff --git a/scripts/units/unit_appearance.gd.uid b/scripts/units/unit_appearance.gd.uid new file mode 100644 index 0000000..750dab4 --- /dev/null +++ b/scripts/units/unit_appearance.gd.uid @@ -0,0 +1 @@ +uid://b402hsmbaj536 diff --git a/scripts/units/unit_appearance_set.gd b/scripts/units/unit_appearance_set.gd new file mode 100644 index 0000000..48bd70c --- /dev/null +++ b/scripts/units/unit_appearance_set.gd @@ -0,0 +1,3 @@ +class_name UnitAppearanceSet extends Resource + +@export var deployed_sprite_sheet: SpriteFrames diff --git a/scripts/units/unit_appearance_set.gd.uid b/scripts/units/unit_appearance_set.gd.uid new file mode 100644 index 0000000..1688835 --- /dev/null +++ b/scripts/units/unit_appearance_set.gd.uid @@ -0,0 +1 @@ +uid://divxkbo321ql