diff --git a/actors/boss/boss.tscn b/actors/boss/boss.tscn index 170c628..c143387 100644 --- a/actors/boss/boss.tscn +++ b/actors/boss/boss.tscn @@ -5,7 +5,7 @@ [ext_resource type="Script" path="res://core/hurtbox.gd" id="3_hurtbox"] [ext_resource type="Script" path="res://core/hitbox.gd" id="4_hitbox"] [ext_resource type="Script" path="res://visuals/death_effect.gd" id="5_death_effect"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/death_dissolve.png" id="6_death_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/death.png" id="6_death_texture"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_body"] size = Vector2(54, 104) @@ -22,11 +22,11 @@ collision_mask = 1 script = ExtResource("1_boss") [node name="Sprite" type="AnimatedSprite2D" parent="."] +position = Vector2(0, -48) +scale = Vector2(0.4, 0.4) sprite_frames = ExtResource("2_frames") animation = &"gate_warden_idle" autoplay = "gate_warden_idle" -centered = false -offset = Vector2(-96, -176) [node name="Body" type="CollisionShape2D" parent="."] position = Vector2(0, -52) @@ -51,10 +51,10 @@ position = Vector2(66, -58) shape = SubResource("RectangleShape2D_hit") [node name="DeathEffect" type="Sprite2D" parent="."] -position = Vector2(0, -88) -scale = Vector2(2, 2) +position = Vector2(0, -28) +scale = Vector2(0.8, 0.8) texture = ExtResource("6_death_texture") -hframes = 8 +hframes = 6 visible = false z_index = 3 modulate = Color(1, 1, 1, 0.72) diff --git a/actors/boss/boss_frames.tres b/actors/boss/boss_frames.tres index fc3aaa8..ab5b1d6 100644 --- a/actors/boss/boss_frames.tres +++ b/actors/boss/boss_frames.tres @@ -2,111 +2,111 @@ ; Do not hand-edit: re-run the generator instead. [gd_resource type="SpriteFrames" load_steps=31 format=3] -[ext_resource type="Texture2D" path="res://assets/boss/boss_idle.png" id="1_idle"] -[ext_resource type="Texture2D" path="res://assets/boss/boss_run.png" id="2_run"] -[ext_resource type="Texture2D" path="res://assets/boss/boss_attack.png" id="3_attack"] -[ext_resource type="Texture2D" path="res://assets/boss/boss_hurt.png" id="4_hurt"] -[ext_resource type="Texture2D" path="res://assets/boss/boss_death.png" id="5_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_idle.png" id="1_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_walk.png" id="2_run"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_attack.png" id="3_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_hurt.png" id="4_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_death.png" id="5_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_idle_0"] atlas = ExtResource("1_idle") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_1"] atlas = ExtResource("1_idle") -region = Rect2(96, 0, 96, 96) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_2"] atlas = ExtResource("1_idle") -region = Rect2(192, 0, 96, 96) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_3"] atlas = ExtResource("1_idle") -region = Rect2(288, 0, 96, 96) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_0"] atlas = ExtResource("2_run") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_1"] atlas = ExtResource("2_run") -region = Rect2(96, 0, 96, 96) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_2"] atlas = ExtResource("2_run") -region = Rect2(192, 0, 96, 96) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_3"] atlas = ExtResource("2_run") -region = Rect2(288, 0, 96, 96) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_4"] atlas = ExtResource("2_run") -region = Rect2(384, 0, 96, 96) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_run_5"] atlas = ExtResource("2_run") -region = Rect2(480, 0, 96, 96) +region = Rect2(1600, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_0"] atlas = ExtResource("3_attack") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_1"] atlas = ExtResource("3_attack") -region = Rect2(96, 0, 96, 96) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_2"] atlas = ExtResource("3_attack") -region = Rect2(192, 0, 96, 96) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_3"] atlas = ExtResource("3_attack") -region = Rect2(288, 0, 96, 96) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_4"] atlas = ExtResource("3_attack") -region = Rect2(384, 0, 96, 96) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_0"] atlas = ExtResource("4_hurt") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_1"] atlas = ExtResource("4_hurt") -region = Rect2(96, 0, 96, 96) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_0"] atlas = ExtResource("5_death") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_1"] atlas = ExtResource("5_death") -region = Rect2(96, 0, 96, 96) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_2"] atlas = ExtResource("5_death") -region = Rect2(192, 0, 96, 96) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_3"] atlas = ExtResource("5_death") -region = Rect2(288, 0, 96, 96) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_4"] atlas = ExtResource("5_death") -region = Rect2(384, 0, 96, 96) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_5"] atlas = ExtResource("5_death") -region = Rect2(480, 0, 96, 96) +region = Rect2(1600, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_6"] atlas = ExtResource("5_death") -region = Rect2(576, 0, 96, 96) +region = Rect2(1920, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_death_7"] atlas = ExtResource("5_death") -region = Rect2(672, 0, 96, 96) +region = Rect2(2240, 0, 320, 256) [resource] animations = [{ @@ -125,7 +125,7 @@ animations = [{ }], "loop": true, "name": &"idle", -"speed": 6.0 +"speed": 5.0 }, { "frames": [{ "duration": 1.0, @@ -148,7 +148,7 @@ animations = [{ }], "loop": true, "name": &"run", -"speed": 8.0 +"speed": 7.0 }, { "frames": [{ "duration": 1.0, @@ -168,7 +168,7 @@ animations = [{ }], "loop": false, "name": &"attack", -"speed": 10.0 +"speed": 9.0 }, { "frames": [{ "duration": 1.0, @@ -179,7 +179,7 @@ animations = [{ }], "loop": false, "name": &"hurt", -"speed": 8.0 +"speed": 7.0 }, { "frames": [{ "duration": 1.0, diff --git a/actors/enemies/ghost_archer.tscn b/actors/enemies/ghost_archer.tscn index 049bab5..c9fa3e3 100644 --- a/actors/enemies/ghost_archer.tscn +++ b/actors/enemies/ghost_archer.tscn @@ -5,7 +5,7 @@ [ext_resource type="SpriteFrames" path="res://assets_v2/godot/ghost_archer_frames.tres" id="3_frames"] [ext_resource type="Resource" path="res://data/actors/ghost_archer_tactics.tres" id="4_tactics"] [ext_resource type="Script" path="res://visuals/death_effect.gd" id="5_death_effect"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/death_dissolve.png" id="6_death_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/death.png" id="6_death_texture"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_v2_body"] size = Vector2(20, 48) @@ -21,12 +21,11 @@ script = ExtResource("2_script") archer_config = ExtResource("4_tactics") [node name="Sprite" parent="." index="0"] +position = Vector2(0, -25.2) +scale = Vector2(0.36, 0.36) sprite_frames = ExtResource("3_frames") animation = &"ghost_archer_idle" autoplay = "ghost_archer_idle" -position = Vector2(0, 0) -centered = false -offset = Vector2(-48, -88) [node name="Body" parent="." index="1"] position = Vector2(0, -24) @@ -41,9 +40,10 @@ disabled = true shape = SubResource("RectangleShape2D_v2_hit") [node name="DeathEffect" type="Sprite2D" parent="." index="4"] -position = Vector2(0, -44) +position = Vector2(0, -20) +scale = Vector2(0.62, 0.62) texture = ExtResource("6_death_texture") -hframes = 8 +hframes = 6 visible = false z_index = 3 modulate = Color(1, 1, 1, 0.72) diff --git a/actors/enemies/ghost_archer_frames.tres b/actors/enemies/ghost_archer_frames.tres index 0a8a900..1100a07 100644 --- a/actors/enemies/ghost_archer_frames.tres +++ b/actors/enemies/ghost_archer_frames.tres @@ -2,91 +2,91 @@ ; Do not hand-edit: re-run the generator instead. [gd_resource type="SpriteFrames" load_steps=26 format=3] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_archer_idle.png" id="1_idle"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_archer_run.png" id="2_run"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_archer_attack.png" id="3_attack"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_archer_hurt.png" id="4_hurt"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_archer_death.png" id="5_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_idle.png" id="1_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_walk.png" id="2_run"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_attack.png" id="3_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_hurt.png" id="4_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_death.png" id="5_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_idle_0"] atlas = ExtResource("1_idle") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_1"] atlas = ExtResource("1_idle") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_2"] atlas = ExtResource("1_idle") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_3"] atlas = ExtResource("1_idle") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_0"] atlas = ExtResource("2_run") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_1"] atlas = ExtResource("2_run") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_2"] atlas = ExtResource("2_run") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_3"] atlas = ExtResource("2_run") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_4"] atlas = ExtResource("2_run") -region = Rect2(192, 0, 48, 48) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_5"] atlas = ExtResource("2_run") -region = Rect2(240, 0, 48, 48) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_0"] atlas = ExtResource("3_attack") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_1"] atlas = ExtResource("3_attack") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_2"] atlas = ExtResource("3_attack") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_3"] atlas = ExtResource("3_attack") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_0"] atlas = ExtResource("4_hurt") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_1"] atlas = ExtResource("4_hurt") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_0"] atlas = ExtResource("5_death") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_1"] atlas = ExtResource("5_death") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_2"] atlas = ExtResource("5_death") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_3"] atlas = ExtResource("5_death") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [resource] animations = [{ @@ -105,7 +105,7 @@ animations = [{ }], "loop": true, "name": &"idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -128,7 +128,7 @@ animations = [{ }], "loop": true, "name": &"run", -"speed": 10.0 +"speed": 9.0 }, { "frames": [{ "duration": 1.0, @@ -145,7 +145,7 @@ animations = [{ }], "loop": false, "name": &"attack", -"speed": 12.0 +"speed": 10.0 }, { "frames": [{ "duration": 1.0, @@ -156,7 +156,7 @@ animations = [{ }], "loop": false, "name": &"hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, @@ -173,5 +173,5 @@ animations = [{ }], "loop": false, "name": &"death", -"speed": 8.0 +"speed": 7.0 }] diff --git a/actors/enemies/ghost_arrow.tscn b/actors/enemies/ghost_arrow.tscn index 1439eab..2c5fc35 100644 --- a/actors/enemies/ghost_arrow.tscn +++ b/actors/enemies/ghost_arrow.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=4 format=3] [ext_resource type="Script" path="res://actors/enemies/ghost_arrow.gd" id="1_arrow"] -[ext_resource type="Texture2D" path="res://assets_v2/projectiles/ghost_fire_arrow.png" id="2_arrow_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/projectiles/ghost_arrow.png" id="2_visual"] [sub_resource type="CapsuleShape2D" id="CapsuleShape2D_arrow"] radius = 2.0 @@ -13,7 +13,8 @@ collision_mask = 9 script = ExtResource("1_arrow") [node name="Visual" type="Sprite2D" parent="."] -texture = ExtResource("2_arrow_texture") +scale = Vector2(0.5, 0.5) +texture = ExtResource("2_visual") [node name="FallbackVisual" type="Polygon2D" parent="."] polygon = PackedVector2Array(-7, -1, 4, -1, 4, -3, 8, 0, 4, 3, 4, 1, -7, 1) diff --git a/actors/enemies/ghost_melee.tscn b/actors/enemies/ghost_melee.tscn index 92f3a25..7b06052 100644 --- a/actors/enemies/ghost_melee.tscn +++ b/actors/enemies/ghost_melee.tscn @@ -4,7 +4,7 @@ [ext_resource type="SpriteFrames" path="res://assets_v2/godot/melee_ghost_frames.tres" id="2_frames"] [ext_resource type="Script" path="res://actors/enemies/melee_ghost.gd" id="3_script"] [ext_resource type="Script" path="res://visuals/death_effect.gd" id="4_death_effect"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/death_dissolve.png" id="5_death_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/death.png" id="5_death_texture"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_v2_body"] size = Vector2(22, 48) @@ -19,12 +19,11 @@ size = Vector2(46, 30) script = ExtResource("3_script") [node name="Sprite" parent="." index="0"] +position = Vector2(0, -25.2) +scale = Vector2(0.36, 0.36) sprite_frames = ExtResource("2_frames") animation = &"melee_ghost_idle" autoplay = "melee_ghost_idle" -position = Vector2(0, 0) -centered = false -offset = Vector2(-48, -90) [node name="Body" parent="." index="1"] position = Vector2(0, -24) @@ -39,9 +38,10 @@ position = Vector2(30, -36) shape = SubResource("RectangleShape2D_v2_hit") [node name="DeathEffect" type="Sprite2D" parent="." index="4"] -position = Vector2(0, -45) +position = Vector2(0, -20) +scale = Vector2(0.62, 0.62) texture = ExtResource("5_death_texture") -hframes = 8 +hframes = 6 visible = false z_index = 3 modulate = Color(1, 1, 1, 0.72) diff --git a/actors/enemies/ghost_melee_frames.tres b/actors/enemies/ghost_melee_frames.tres index 7628485..0170a88 100644 --- a/actors/enemies/ghost_melee_frames.tres +++ b/actors/enemies/ghost_melee_frames.tres @@ -2,91 +2,91 @@ ; Do not hand-edit: re-run the generator instead. [gd_resource type="SpriteFrames" load_steps=26 format=3] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_melee_idle.png" id="1_idle"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_melee_run.png" id="2_run"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_melee_attack.png" id="3_attack"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_melee_hurt.png" id="4_hurt"] -[ext_resource type="Texture2D" path="res://assets/enemy/ghost_melee_death.png" id="5_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_idle.png" id="1_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_walk.png" id="2_run"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_attack.png" id="3_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_hurt.png" id="4_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_death.png" id="5_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_idle_0"] atlas = ExtResource("1_idle") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_1"] atlas = ExtResource("1_idle") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_2"] atlas = ExtResource("1_idle") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_3"] atlas = ExtResource("1_idle") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_0"] atlas = ExtResource("2_run") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_1"] atlas = ExtResource("2_run") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_2"] atlas = ExtResource("2_run") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_3"] atlas = ExtResource("2_run") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_4"] atlas = ExtResource("2_run") -region = Rect2(192, 0, 48, 48) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_5"] atlas = ExtResource("2_run") -region = Rect2(240, 0, 48, 48) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_0"] atlas = ExtResource("3_attack") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_1"] atlas = ExtResource("3_attack") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_2"] atlas = ExtResource("3_attack") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_3"] atlas = ExtResource("3_attack") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_0"] atlas = ExtResource("4_hurt") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_1"] atlas = ExtResource("4_hurt") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_0"] atlas = ExtResource("5_death") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_1"] atlas = ExtResource("5_death") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_2"] atlas = ExtResource("5_death") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_3"] atlas = ExtResource("5_death") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [resource] animations = [{ @@ -105,7 +105,7 @@ animations = [{ }], "loop": true, "name": &"idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -128,7 +128,7 @@ animations = [{ }], "loop": true, "name": &"run", -"speed": 10.0 +"speed": 9.0 }, { "frames": [{ "duration": 1.0, @@ -145,7 +145,7 @@ animations = [{ }], "loop": false, "name": &"attack", -"speed": 12.0 +"speed": 10.0 }, { "frames": [{ "duration": 1.0, @@ -156,7 +156,7 @@ animations = [{ }], "loop": false, "name": &"hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, @@ -173,5 +173,5 @@ animations = [{ }], "loop": false, "name": &"death", -"speed": 8.0 +"speed": 7.0 }] diff --git a/actors/player/player.tscn b/actors/player/player.tscn index 5284592..ca04743 100644 --- a/actors/player/player.tscn +++ b/actors/player/player.tscn @@ -5,9 +5,9 @@ [ext_resource type="Script" path="res://core/hurtbox.gd" id="3_hurtbox"] [ext_resource type="Script" path="res://core/hitbox.gd" id="4_hitbox"] [ext_resource type="Script" path="res://visuals/player_slash_visual.gd" id="5_slash"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/blade_slash.png" id="6_slash_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/slash.png" id="6_slash_texture"] [ext_resource type="Script" path="res://visuals/death_effect.gd" id="7_death_effect"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/death_dissolve.png" id="8_death_texture"] +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/death.png" id="8_death_texture"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_body"] size = Vector2(18, 44) @@ -24,25 +24,27 @@ collision_mask = 1 script = ExtResource("1_player") [node name="Sprite" type="AnimatedSprite2D" parent="."] +position = Vector2(0, -25.2) +scale = Vector2(0.36, 0.36) sprite_frames = ExtResource("2_frames") animation = &"player_idle" autoplay = "player_idle" -centered = false -offset = Vector2(-48, -88) [node name="SlashVisual" type="Sprite2D" parent="."] -position = Vector2(18, -48) +position = Vector2(18, -26) +scale = Vector2(0.52, 0.52) texture = ExtResource("6_slash_texture") -hframes = 6 +hframes = 4 visible = false z_index = 2 script = ExtResource("5_slash") playback_fps = 18.0 [node name="DeathEffect" type="Sprite2D" parent="."] -position = Vector2(0, -44) +position = Vector2(0, -20) +scale = Vector2(0.62, 0.62) texture = ExtResource("8_death_texture") -hframes = 8 +hframes = 6 visible = false z_index = 3 modulate = Color(1, 1, 1, 0.72) diff --git a/actors/player/player_frames.tres b/actors/player/player_frames.tres index 1fdbe85..d7abeb8 100644 --- a/actors/player/player_frames.tres +++ b/actors/player/player_frames.tres @@ -2,108 +2,108 @@ ; Do not hand-edit: re-run the generator instead. [gd_resource type="SpriteFrames" load_steps=31 format=3] -[ext_resource type="Texture2D" path="res://assets/player/player_idle.png" id="1_idle"] -[ext_resource type="Texture2D" path="res://assets/player/player_run.png" id="2_run"] -[ext_resource type="Texture2D" path="res://assets/player/player_jump.png" id="3_jump"] -[ext_resource type="Texture2D" path="res://assets/player/player_attack.png" id="4_attack"] -[ext_resource type="Texture2D" path="res://assets/player/player_hurt.png" id="5_hurt"] -[ext_resource type="Texture2D" path="res://assets/player/player_death.png" id="6_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_idle.png" id="1_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_walk.png" id="2_run"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_idle.png" id="3_jump"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_attack.png" id="4_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_hurt.png" id="5_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_death.png" id="6_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_idle_0"] atlas = ExtResource("1_idle") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_1"] atlas = ExtResource("1_idle") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_2"] atlas = ExtResource("1_idle") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_idle_3"] atlas = ExtResource("1_idle") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_0"] atlas = ExtResource("2_run") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_1"] atlas = ExtResource("2_run") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_2"] atlas = ExtResource("2_run") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_3"] atlas = ExtResource("2_run") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_4"] atlas = ExtResource("2_run") -region = Rect2(192, 0, 48, 48) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_run_5"] atlas = ExtResource("2_run") -region = Rect2(240, 0, 48, 48) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_jump_0"] atlas = ExtResource("3_jump") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_jump_1"] atlas = ExtResource("3_jump") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_0"] atlas = ExtResource("4_attack") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_1"] atlas = ExtResource("4_attack") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_2"] atlas = ExtResource("4_attack") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_attack_3"] atlas = ExtResource("4_attack") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_0"] atlas = ExtResource("5_hurt") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_hurt_1"] atlas = ExtResource("5_hurt") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_0"] atlas = ExtResource("6_death") -region = Rect2(0, 0, 48, 48) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_1"] atlas = ExtResource("6_death") -region = Rect2(48, 0, 48, 48) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_2"] atlas = ExtResource("6_death") -region = Rect2(96, 0, 48, 48) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_3"] atlas = ExtResource("6_death") -region = Rect2(144, 0, 48, 48) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_4"] atlas = ExtResource("6_death") -region = Rect2(192, 0, 48, 48) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_death_5"] atlas = ExtResource("6_death") -region = Rect2(240, 0, 48, 48) +region = Rect2(960, 0, 192, 160) [resource] animations = [{ @@ -122,7 +122,7 @@ animations = [{ }], "loop": true, "name": &"idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -145,7 +145,7 @@ animations = [{ }], "loop": true, "name": &"run", -"speed": 12.0 +"speed": 10.0 }, { "frames": [{ "duration": 1.0, @@ -173,7 +173,7 @@ animations = [{ }], "loop": false, "name": &"attack", -"speed": 14.0 +"speed": 12.0 }, { "frames": [{ "duration": 1.0, @@ -184,7 +184,7 @@ animations = [{ }], "loop": false, "name": &"hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, diff --git a/assets_v2/godot/gate_warden_frames.tres b/assets_v2/godot/gate_warden_frames.tres index 88d4f0c..b76e3a5 100644 --- a/assets_v2/godot/gate_warden_frames.tres +++ b/assets_v2/godot/gate_warden_frames.tres @@ -1,229 +1,173 @@ -; Generated by assets_v2/tools/gen_metadata.py for the V2 (Steam Alpha) art set. +; Generated by tools/generate_sprite_frames.py from docs/ART_SPEC.md. ; Do not hand-edit: re-run the generator instead. -[gd_resource type="SpriteFrames" load_steps=61 format=3] +[gd_resource type="SpriteFrames" load_steps=47 format=3] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_idle.png" id="1_gate_warden_idle"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_walk.png" id="2_gate_warden_walk"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_attack_1.png" id="3_gate_warden_attack_1"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_attack_2.png" id="4_gate_warden_attack_2"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_hurt.png" id="5_gate_warden_hurt"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/gate_warden/gate_warden_death.png" id="6_gate_warden_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_idle.png" id="1_gate_warden_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_walk.png" id="2_gate_warden_walk"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_attack.png" id="3_gate_warden_attack_1"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_attack.png" id="4_gate_warden_attack_2"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_hurt.png" id="5_gate_warden_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/gate_warden/gate_warden_death.png" id="6_gate_warden_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_0"] atlas = ExtResource("1_gate_warden_idle") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_1"] atlas = ExtResource("1_gate_warden_idle") -region = Rect2(192, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_2"] atlas = ExtResource("1_gate_warden_idle") -region = Rect2(384, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_3"] atlas = ExtResource("1_gate_warden_idle") -region = Rect2(576, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_4"] -atlas = ExtResource("1_gate_warden_idle") -region = Rect2(768, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_5"] -atlas = ExtResource("1_gate_warden_idle") -region = Rect2(960, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_6"] -atlas = ExtResource("1_gate_warden_idle") -region = Rect2(1152, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_idle_7"] -atlas = ExtResource("1_gate_warden_idle") -region = Rect2(1344, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_0"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_1"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(192, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_2"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(384, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_3"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(576, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_4"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(768, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_5"] atlas = ExtResource("2_gate_warden_walk") -region = Rect2(960, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_6"] -atlas = ExtResource("2_gate_warden_walk") -region = Rect2(1152, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_walk_7"] -atlas = ExtResource("2_gate_warden_walk") -region = Rect2(1344, 0, 192, 192) +region = Rect2(1600, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_0"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_1"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(192, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_2"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(384, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_3"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(576, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_4"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(768, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_5"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(960, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_6"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(1152, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_7"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(1344, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_8"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(1536, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_1_9"] atlas = ExtResource("3_gate_warden_attack_1") -region = Rect2(1728, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_0"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_1"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(192, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_2"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(384, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_3"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(576, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_4"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(768, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_5"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(960, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_6"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(1152, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_7"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(1344, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_8"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(1536, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_9"] atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(1728, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_10"] -atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(1920, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_attack_2_11"] -atlas = ExtResource("4_gate_warden_attack_2") -region = Rect2(2112, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_hurt_0"] atlas = ExtResource("5_gate_warden_hurt") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_hurt_1"] atlas = ExtResource("5_gate_warden_hurt") -region = Rect2(192, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_hurt_2"] -atlas = ExtResource("5_gate_warden_hurt") -region = Rect2(384, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_hurt_3"] -atlas = ExtResource("5_gate_warden_hurt") -region = Rect2(576, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_0"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(0, 0, 192, 192) +region = Rect2(0, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_1"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(192, 0, 192, 192) +region = Rect2(320, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_2"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(384, 0, 192, 192) +region = Rect2(640, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_3"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(576, 0, 192, 192) +region = Rect2(960, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_4"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(768, 0, 192, 192) +region = Rect2(1280, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_5"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(960, 0, 192, 192) +region = Rect2(1600, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_6"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(1152, 0, 192, 192) +region = Rect2(1920, 0, 320, 256) [sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_7"] atlas = ExtResource("6_gate_warden_death") -region = Rect2(1344, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_8"] -atlas = ExtResource("6_gate_warden_death") -region = Rect2(1536, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_9"] -atlas = ExtResource("6_gate_warden_death") -region = Rect2(1728, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_10"] -atlas = ExtResource("6_gate_warden_death") -region = Rect2(1920, 0, 192, 192) - -[sub_resource type="AtlasTexture" id="AtlasTexture_gate_warden_death_11"] -atlas = ExtResource("6_gate_warden_death") -region = Rect2(2112, 0, 192, 192) +region = Rect2(2240, 0, 320, 256) [resource] animations = [{ @@ -239,22 +183,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_gate_warden_idle_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_idle_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_idle_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_idle_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_idle_7") }], "loop": true, "name": &"gate_warden_idle", -"speed": 6.0 +"speed": 5.0 }, { "frames": [{ "duration": 1.0, @@ -274,16 +206,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_gate_warden_walk_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_walk_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_walk_7") }], "loop": true, "name": &"gate_warden_walk", -"speed": 8.0 +"speed": 7.0 }, { "frames": [{ "duration": 1.0, @@ -350,12 +276,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_gate_warden_attack_2_9") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_attack_2_10") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_attack_2_11") }], "loop": false, "name": &"gate_warden_attack_2", @@ -367,16 +287,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_gate_warden_hurt_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_hurt_2") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_hurt_3") }], "loop": false, "name": &"gate_warden_hurt", -"speed": 8.0 +"speed": 7.0 }, { "frames": [{ "duration": 1.0, @@ -402,18 +316,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_gate_warden_death_7") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_death_8") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_death_9") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_death_10") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_gate_warden_death_11") }], "loop": false, "name": &"gate_warden_death", diff --git a/assets_v2/godot/ghost_archer_frames.tres b/assets_v2/godot/ghost_archer_frames.tres index 61c9188..3f1d100 100644 --- a/assets_v2/godot/ghost_archer_frames.tres +++ b/assets_v2/godot/ghost_archer_frames.tres @@ -1,157 +1,117 @@ -; Generated by assets_v2/tools/gen_metadata.py for the V2 (Steam Alpha) art set. +; Generated by tools/generate_sprite_frames.py from docs/ART_SPEC.md. ; Do not hand-edit: re-run the generator instead. -[gd_resource type="SpriteFrames" load_steps=43 format=3] +[gd_resource type="SpriteFrames" load_steps=33 format=3] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_idle.png" id="1_ghost_archer_idle"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_retreat.png" id="2_ghost_archer_retreat"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_aim.png" id="3_ghost_archer_aim"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_shoot.png" id="4_ghost_archer_shoot"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_hurt.png" id="5_ghost_archer_hurt"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/ghost_archer/ghost_archer_death.png" id="6_ghost_archer_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_idle.png" id="1_ghost_archer_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_walk.png" id="2_ghost_archer_retreat"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_attack.png" id="3_ghost_archer_aim"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_attack.png" id="4_ghost_archer_shoot"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_hurt.png" id="5_ghost_archer_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_archer/ghost_archer_death.png" id="6_ghost_archer_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_0"] atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_1"] atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_2"] atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_3"] atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(288, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_4"] -atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(384, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_idle_5"] -atlas = ExtResource("1_ghost_archer_idle") -region = Rect2(480, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_0"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_1"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_2"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_3"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(288, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_4"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(384, 0, 96, 96) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_5"] atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_6"] -atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_retreat_7"] -atlas = ExtResource("2_ghost_archer_retreat") -region = Rect2(672, 0, 96, 96) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_0"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_1"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(96, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_2"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_3"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_4"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(384, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_aim_5"] atlas = ExtResource("3_ghost_archer_aim") -region = Rect2(480, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_shoot_0"] atlas = ExtResource("4_ghost_archer_shoot") -region = Rect2(0, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_shoot_1"] atlas = ExtResource("4_ghost_archer_shoot") -region = Rect2(96, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_shoot_2"] atlas = ExtResource("4_ghost_archer_shoot") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_shoot_3"] atlas = ExtResource("4_ghost_archer_shoot") -region = Rect2(288, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_hurt_0"] atlas = ExtResource("5_ghost_archer_hurt") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_hurt_1"] atlas = ExtResource("5_ghost_archer_hurt") -region = Rect2(96, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_hurt_2"] -atlas = ExtResource("5_ghost_archer_hurt") -region = Rect2(192, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_hurt_3"] -atlas = ExtResource("5_ghost_archer_hurt") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_0"] atlas = ExtResource("6_ghost_archer_death") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_1"] atlas = ExtResource("6_ghost_archer_death") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_2"] atlas = ExtResource("6_ghost_archer_death") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_3"] atlas = ExtResource("6_ghost_archer_death") -region = Rect2(288, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_4"] -atlas = ExtResource("6_ghost_archer_death") -region = Rect2(384, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_5"] -atlas = ExtResource("6_ghost_archer_death") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_6"] -atlas = ExtResource("6_ghost_archer_death") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ghost_archer_death_7"] -atlas = ExtResource("6_ghost_archer_death") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [resource] animations = [{ @@ -167,16 +127,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_ghost_archer_idle_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_idle_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_idle_5") }], "loop": true, "name": &"ghost_archer_idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -196,16 +150,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_ghost_archer_retreat_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_retreat_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_retreat_7") }], "loop": true, "name": &"ghost_archer_retreat", -"speed": 10.0 +"speed": 9.0 }, { "frames": [{ "duration": 1.0, @@ -253,16 +201,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_ghost_archer_hurt_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_hurt_2") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_hurt_3") }], "loop": false, "name": &"ghost_archer_hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, @@ -276,20 +218,8 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_ghost_archer_death_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_death_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_death_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_death_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ghost_archer_death_7") }], "loop": false, "name": &"ghost_archer_death", -"speed": 8.0 +"speed": 7.0 }] diff --git a/assets_v2/godot/melee_ghost_frames.tres b/assets_v2/godot/melee_ghost_frames.tres index 8bf3c74..a639058 100644 --- a/assets_v2/godot/melee_ghost_frames.tres +++ b/assets_v2/godot/melee_ghost_frames.tres @@ -1,148 +1,108 @@ -; Generated by assets_v2/tools/gen_metadata.py for the V2 (Steam Alpha) art set. +; Generated by tools/generate_sprite_frames.py from docs/ART_SPEC.md. ; Do not hand-edit: re-run the generator instead. -[gd_resource type="SpriteFrames" load_steps=40 format=3] +[gd_resource type="SpriteFrames" load_steps=30 format=3] -[ext_resource type="Texture2D" path="res://assets_v2/characters/melee_ghost/melee_ghost_idle.png" id="1_melee_ghost_idle"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/melee_ghost/melee_ghost_walk.png" id="2_melee_ghost_walk"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/melee_ghost/melee_ghost_attack.png" id="3_melee_ghost_attack"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/melee_ghost/melee_ghost_hurt.png" id="4_melee_ghost_hurt"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/melee_ghost/melee_ghost_death.png" id="5_melee_ghost_death"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_idle.png" id="1_melee_ghost_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_walk.png" id="2_melee_ghost_walk"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_attack.png" id="3_melee_ghost_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_hurt.png" id="4_melee_ghost_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/ghost_melee/ghost_melee_death.png" id="5_melee_ghost_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_0"] atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_1"] atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_2"] atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_3"] atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(288, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_4"] -atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(384, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_idle_5"] -atlas = ExtResource("1_melee_ghost_idle") -region = Rect2(480, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_0"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_1"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_2"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_3"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(288, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_4"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(384, 0, 96, 96) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_5"] atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_6"] -atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_walk_7"] -atlas = ExtResource("2_melee_ghost_walk") -region = Rect2(672, 0, 96, 96) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_0"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_1"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(96, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_2"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_3"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_4"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(384, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_5"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(480, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_6"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(576, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_attack_7"] atlas = ExtResource("3_melee_ghost_attack") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_hurt_0"] atlas = ExtResource("4_melee_ghost_hurt") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_hurt_1"] atlas = ExtResource("4_melee_ghost_hurt") -region = Rect2(96, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_hurt_2"] -atlas = ExtResource("4_melee_ghost_hurt") -region = Rect2(192, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_hurt_3"] -atlas = ExtResource("4_melee_ghost_hurt") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_0"] atlas = ExtResource("5_melee_ghost_death") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_1"] atlas = ExtResource("5_melee_ghost_death") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_2"] atlas = ExtResource("5_melee_ghost_death") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_3"] atlas = ExtResource("5_melee_ghost_death") -region = Rect2(288, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_4"] -atlas = ExtResource("5_melee_ghost_death") -region = Rect2(384, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_5"] -atlas = ExtResource("5_melee_ghost_death") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_6"] -atlas = ExtResource("5_melee_ghost_death") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_melee_ghost_death_7"] -atlas = ExtResource("5_melee_ghost_death") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [resource] animations = [{ @@ -158,16 +118,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_melee_ghost_idle_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_idle_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_idle_5") }], "loop": true, "name": &"melee_ghost_idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -187,16 +141,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_melee_ghost_walk_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_walk_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_walk_7") }], "loop": true, "name": &"melee_ghost_walk", -"speed": 8.0 +"speed": 9.0 }, { "frames": [{ "duration": 1.0, @@ -233,16 +181,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_melee_ghost_hurt_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_hurt_2") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_hurt_3") }], "loop": false, "name": &"melee_ghost_hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, @@ -256,20 +198,8 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_melee_ghost_death_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_death_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_death_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_death_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_melee_ghost_death_7") }], "loop": false, "name": &"melee_ghost_death", -"speed": 8.0 +"speed": 7.0 }] diff --git a/assets_v2/godot/player_frames.tres b/assets_v2/godot/player_frames.tres index 62a6e46..3724014 100644 --- a/assets_v2/godot/player_frames.tres +++ b/assets_v2/godot/player_frames.tres @@ -1,264 +1,200 @@ -; Generated by assets_v2/tools/gen_metadata.py for the V2 (Steam Alpha) art set. +; Generated by tools/generate_sprite_frames.py from docs/ART_SPEC.md. ; Do not hand-edit: re-run the generator instead. -[gd_resource type="SpriteFrames" load_steps=72 format=3] - -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_idle.png" id="1_player_idle"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_run.png" id="2_player_run"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_jump.png" id="3_player_jump"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_fall.png" id="4_player_fall"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_light_attack_1.png" id="5_player_light_attack_1"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_light_attack_2.png" id="6_player_light_attack_2"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_heavy_attack.png" id="7_player_heavy_attack"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_hurt.png" id="8_player_hurt"] -[ext_resource type="Texture2D" path="res://assets_v2/characters/player/player_death.png" id="9_player_death"] +[gd_resource type="SpriteFrames" load_steps=56 format=3] + +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_idle.png" id="1_player_idle"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_walk.png" id="2_player_run"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_idle.png" id="3_player_jump"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_idle.png" id="4_player_fall"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_attack.png" id="5_player_light_attack_1"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_attack.png" id="6_player_light_attack_2"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_attack.png" id="7_player_heavy_attack"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_hurt.png" id="8_player_hurt"] +[ext_resource type="Texture2D" path="res://assets_v3/production/player/player_death.png" id="9_player_death"] [sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_0"] atlas = ExtResource("1_player_idle") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_1"] atlas = ExtResource("1_player_idle") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_2"] atlas = ExtResource("1_player_idle") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_3"] atlas = ExtResource("1_player_idle") -region = Rect2(288, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_4"] -atlas = ExtResource("1_player_idle") -region = Rect2(384, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_5"] -atlas = ExtResource("1_player_idle") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_6"] -atlas = ExtResource("1_player_idle") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_idle_7"] -atlas = ExtResource("1_player_idle") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_0"] atlas = ExtResource("2_player_run") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_1"] atlas = ExtResource("2_player_run") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_2"] atlas = ExtResource("2_player_run") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_3"] atlas = ExtResource("2_player_run") -region = Rect2(288, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_4"] atlas = ExtResource("2_player_run") -region = Rect2(384, 0, 96, 96) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_run_5"] atlas = ExtResource("2_player_run") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_run_6"] -atlas = ExtResource("2_player_run") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_run_7"] -atlas = ExtResource("2_player_run") -region = Rect2(672, 0, 96, 96) +region = Rect2(960, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_jump_0"] atlas = ExtResource("3_player_jump") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_jump_1"] atlas = ExtResource("3_player_jump") -region = Rect2(96, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_jump_2"] -atlas = ExtResource("3_player_jump") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_fall_0"] atlas = ExtResource("4_player_fall") -region = Rect2(0, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_fall_1"] atlas = ExtResource("4_player_fall") -region = Rect2(96, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_fall_2"] -atlas = ExtResource("4_player_fall") -region = Rect2(192, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_0"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_1"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(96, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_2"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_3"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_4"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(384, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_5"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(480, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_6"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(576, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_1_7"] atlas = ExtResource("5_player_light_attack_1") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_0"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_1"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(96, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_2"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_3"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_4"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(384, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_5"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(480, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_6"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(576, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_light_attack_2_7"] atlas = ExtResource("6_player_light_attack_2") -region = Rect2(672, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_0"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_1"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(96, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_2"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(192, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_3"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_4"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(384, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_5"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(480, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_6"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(576, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_7"] atlas = ExtResource("7_player_heavy_attack") -region = Rect2(672, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_8"] -atlas = ExtResource("7_player_heavy_attack") -region = Rect2(768, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_heavy_attack_9"] -atlas = ExtResource("7_player_heavy_attack") -region = Rect2(864, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_hurt_0"] atlas = ExtResource("8_player_hurt") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_hurt_1"] atlas = ExtResource("8_player_hurt") -region = Rect2(96, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_hurt_2"] -atlas = ExtResource("8_player_hurt") -region = Rect2(192, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_hurt_3"] -atlas = ExtResource("8_player_hurt") -region = Rect2(288, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_0"] atlas = ExtResource("9_player_death") -region = Rect2(0, 0, 96, 96) +region = Rect2(0, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_1"] atlas = ExtResource("9_player_death") -region = Rect2(96, 0, 96, 96) +region = Rect2(192, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_2"] atlas = ExtResource("9_player_death") -region = Rect2(192, 0, 96, 96) +region = Rect2(384, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_3"] atlas = ExtResource("9_player_death") -region = Rect2(288, 0, 96, 96) +region = Rect2(576, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_4"] atlas = ExtResource("9_player_death") -region = Rect2(384, 0, 96, 96) +region = Rect2(768, 0, 192, 160) [sub_resource type="AtlasTexture" id="AtlasTexture_player_death_5"] atlas = ExtResource("9_player_death") -region = Rect2(480, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_death_6"] -atlas = ExtResource("9_player_death") -region = Rect2(576, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_death_7"] -atlas = ExtResource("9_player_death") -region = Rect2(672, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_death_8"] -atlas = ExtResource("9_player_death") -region = Rect2(768, 0, 96, 96) - -[sub_resource type="AtlasTexture" id="AtlasTexture_player_death_9"] -atlas = ExtResource("9_player_death") -region = Rect2(864, 0, 96, 96) +region = Rect2(960, 0, 192, 160) [resource] animations = [{ @@ -274,22 +210,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_idle_3") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_idle_4") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_idle_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_idle_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_idle_7") }], "loop": true, "name": &"player_idle", -"speed": 8.0 +"speed": 6.0 }, { "frames": [{ "duration": 1.0, @@ -309,16 +233,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_run_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_run_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_run_7") }], "loop": true, "name": &"player_run", -"speed": 12.0 +"speed": 10.0 }, { "frames": [{ "duration": 1.0, @@ -326,9 +244,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_jump_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_jump_2") }], "loop": false, "name": &"player_jump", @@ -340,9 +255,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_fall_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_fall_2") }], "loop": false, "name": &"player_fall", @@ -430,12 +342,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_heavy_attack_7") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_heavy_attack_8") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_heavy_attack_9") }], "loop": false, "name": &"player_heavy_attack", @@ -447,16 +353,10 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_hurt_1") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_hurt_2") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_hurt_3") }], "loop": false, "name": &"player_hurt", -"speed": 10.0 +"speed": 8.0 }, { "frames": [{ "duration": 1.0, @@ -476,18 +376,6 @@ animations = [{ }, { "duration": 1.0, "texture": SubResource("AtlasTexture_player_death_5") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_death_6") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_death_7") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_death_8") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_player_death_9") }], "loop": false, "name": &"player_death", diff --git a/assets_v3/production/effects/blood.png b/assets_v3/production/effects/blood.png new file mode 100644 index 0000000..ff7b5e6 Binary files /dev/null and b/assets_v3/production/effects/blood.png differ diff --git a/assets_v3/production/effects/blood.png.import b/assets_v3/production/effects/blood.png.import new file mode 100644 index 0000000..4277b4a --- /dev/null +++ b/assets_v3/production/effects/blood.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf4oeef5wn7ug" +path="res://.godot/imported/blood.png-2193435e274852edc330c8971ab6519a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/effects/blood.png" +dest_files=["res://.godot/imported/blood.png-2193435e274852edc330c8971ab6519a.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=0 diff --git a/assets_v3/production/effects/death.png b/assets_v3/production/effects/death.png new file mode 100644 index 0000000..15b6e5b Binary files /dev/null and b/assets_v3/production/effects/death.png differ diff --git a/assets_v3/production/effects/death.png.import b/assets_v3/production/effects/death.png.import new file mode 100644 index 0000000..da59d7c --- /dev/null +++ b/assets_v3/production/effects/death.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dm66jba7o4ost" +path="res://.godot/imported/death.png-3dedece20a0df8986ff09b6300f8395a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/effects/death.png" +dest_files=["res://.godot/imported/death.png-3dedece20a0df8986ff09b6300f8395a.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=0 diff --git a/assets_v3/production/effects/frame_map.json b/assets_v3/production/effects/frame_map.json new file mode 100644 index 0000000..b7fe8cb --- /dev/null +++ b/assets_v3/production/effects/frame_map.json @@ -0,0 +1,44 @@ +{ + "effects": { + "slash": { + "frame_size": [ + 96, + 64 + ], + "frames": 4, + "fps": 12 + }, + "hit": { + "frame_size": [ + 64, + 64 + ], + "frames": 4, + "fps": 16 + }, + "blood": { + "frame_size": [ + 96, + 64 + ], + "frames": 4, + "fps": 14 + }, + "ghost_fire": { + "frame_size": [ + 64, + 64 + ], + "frames": 6, + "fps": 10 + }, + "death": { + "frame_size": [ + 64, + 80 + ], + "frames": 6, + "fps": 10 + } + } +} diff --git a/assets_v3/production/effects/ghost_fire.png b/assets_v3/production/effects/ghost_fire.png new file mode 100644 index 0000000..da22a53 Binary files /dev/null and b/assets_v3/production/effects/ghost_fire.png differ diff --git a/assets_v3/production/effects/ghost_fire.png.import b/assets_v3/production/effects/ghost_fire.png.import new file mode 100644 index 0000000..ba5ce0d --- /dev/null +++ b/assets_v3/production/effects/ghost_fire.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c6mx7bq3w0o53" +path="res://.godot/imported/ghost_fire.png-19592c923bc5c7913adf09520db1d742.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/effects/ghost_fire.png" +dest_files=["res://.godot/imported/ghost_fire.png-19592c923bc5c7913adf09520db1d742.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=0 diff --git a/assets_v3/production/effects/hit.png b/assets_v3/production/effects/hit.png new file mode 100644 index 0000000..c6ac3c0 Binary files /dev/null and b/assets_v3/production/effects/hit.png differ diff --git a/assets_v3/production/effects/hit.png.import b/assets_v3/production/effects/hit.png.import new file mode 100644 index 0000000..0400fb3 --- /dev/null +++ b/assets_v3/production/effects/hit.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcg6psjyk2cf1" +path="res://.godot/imported/hit.png-b33e9e9afc45a42e6c7ac0a4be5cf17a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/effects/hit.png" +dest_files=["res://.godot/imported/hit.png-b33e9e9afc45a42e6c7ac0a4be5cf17a.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=0 diff --git a/assets_v3/production/effects/metadata.md b/assets_v3/production/effects/metadata.md new file mode 100644 index 0000000..5099355 --- /dev/null +++ b/assets_v3/production/effects/metadata.md @@ -0,0 +1,3 @@ +# Combat Effect Metadata + +Transparent RGBA pixel effects using the approved Art V3 palette. Frame sizes, counts, and FPS are in `frame_map.json`. diff --git a/assets_v3/production/effects/slash.png b/assets_v3/production/effects/slash.png new file mode 100644 index 0000000..1a82e56 Binary files /dev/null and b/assets_v3/production/effects/slash.png differ diff --git a/assets_v3/production/effects/slash.png.import b/assets_v3/production/effects/slash.png.import new file mode 100644 index 0000000..e4cf973 --- /dev/null +++ b/assets_v3/production/effects/slash.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d14f1h0eoeed6" +path="res://.godot/imported/slash.png-8225071f9b88d2ebe984d21fc2e5cd96.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/effects/slash.png" +dest_files=["res://.godot/imported/slash.png-8225071f9b88d2ebe984d21fc2e5cd96.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=0 diff --git a/assets_v3/production/environment/battlefield_fog.png b/assets_v3/production/environment/battlefield_fog.png new file mode 100644 index 0000000..0e93728 Binary files /dev/null and b/assets_v3/production/environment/battlefield_fog.png differ diff --git a/assets_v3/production/environment/battlefield_fog.png.import b/assets_v3/production/environment/battlefield_fog.png.import new file mode 100644 index 0000000..1aa1e46 --- /dev/null +++ b/assets_v3/production/environment/battlefield_fog.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cbuhdj5dp1c6p" +path="res://.godot/imported/battlefield_fog.png-956f16b6eeba0deb7466c74cbf874aff.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/environment/battlefield_fog.png" +dest_files=["res://.godot/imported/battlefield_fog.png-956f16b6eeba0deb7466c74cbf874aff.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=0 diff --git a/assets_v3/production/environment/fortress_gate.png b/assets_v3/production/environment/fortress_gate.png new file mode 100644 index 0000000..8d8a10f Binary files /dev/null and b/assets_v3/production/environment/fortress_gate.png differ diff --git a/assets_v3/production/environment/fortress_gate.png.import b/assets_v3/production/environment/fortress_gate.png.import new file mode 100644 index 0000000..c1a492d --- /dev/null +++ b/assets_v3/production/environment/fortress_gate.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cp6nuwpaebinr" +path="res://.godot/imported/fortress_gate.png-0face645863c6d81644a3d1df095318f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/environment/fortress_gate.png" +dest_files=["res://.godot/imported/fortress_gate.png-0face645863c6d81644a3d1df095318f.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=0 diff --git a/assets_v3/production/environment/stone_floor.png b/assets_v3/production/environment/stone_floor.png new file mode 100644 index 0000000..69d48f2 Binary files /dev/null and b/assets_v3/production/environment/stone_floor.png differ diff --git a/assets_v3/production/environment/stone_floor.png.import b/assets_v3/production/environment/stone_floor.png.import new file mode 100644 index 0000000..d837fec --- /dev/null +++ b/assets_v3/production/environment/stone_floor.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdbaup652008d" +path="res://.godot/imported/stone_floor.png-38fdcd8851a34c52bce26ec1dff96e95.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/environment/stone_floor.png" +dest_files=["res://.godot/imported/stone_floor.png-38fdcd8851a34c52bce26ec1dff96e95.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=0 diff --git a/assets_v3/production/environment/stone_wall.png b/assets_v3/production/environment/stone_wall.png new file mode 100644 index 0000000..917f077 Binary files /dev/null and b/assets_v3/production/environment/stone_wall.png differ diff --git a/assets_v3/production/environment/stone_wall.png.import b/assets_v3/production/environment/stone_wall.png.import new file mode 100644 index 0000000..9d7d036 --- /dev/null +++ b/assets_v3/production/environment/stone_wall.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c6dbu0iknl4qu" +path="res://.godot/imported/stone_wall.png-9e8620aee12aff0a64b083b00163b22c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/environment/stone_wall.png" +dest_files=["res://.godot/imported/stone_wall.png-9e8620aee12aff0a64b083b00163b22c.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=0 diff --git a/assets_v3/production/gate_warden/frame_map.json b/assets_v3/production/gate_warden/frame_map.json new file mode 100644 index 0000000..6b0f53a --- /dev/null +++ b/assets_v3/production/gate_warden/frame_map.json @@ -0,0 +1,44 @@ +{ + "character": "gate_warden", + "frame_size": [ + 320, + 256 + ], + "pivot": [ + 160, + 248 + ], + "foot_position": [ + 160, + 248 + ], + "animations": { + "idle": { + "frames": 4, + "fps": 5, + "loop": true + }, + "walk": { + "frames": 6, + "fps": 7, + "loop": true + }, + "attack": { + "frames": 5, + "fps": 9, + "loop": false, + "hit_frame": 2, + "recovery_frame": 4 + }, + "hurt": { + "frames": 2, + "fps": 7, + "loop": false + }, + "death": { + "frames": 8, + "fps": 6, + "loop": false + } + } +} diff --git a/assets_v3/production/gate_warden/gate_warden_attack.png b/assets_v3/production/gate_warden/gate_warden_attack.png new file mode 100644 index 0000000..3afc2f0 Binary files /dev/null and b/assets_v3/production/gate_warden/gate_warden_attack.png differ diff --git a/assets_v3/production/gate_warden/gate_warden_attack.png.import b/assets_v3/production/gate_warden/gate_warden_attack.png.import new file mode 100644 index 0000000..00e0d25 --- /dev/null +++ b/assets_v3/production/gate_warden/gate_warden_attack.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqb52ix5evfke" +path="res://.godot/imported/gate_warden_attack.png-f9fb38d918bc420096aa8ce7b0b0a46f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/gate_warden/gate_warden_attack.png" +dest_files=["res://.godot/imported/gate_warden_attack.png-f9fb38d918bc420096aa8ce7b0b0a46f.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=0 diff --git a/assets_v3/production/gate_warden/gate_warden_death.png b/assets_v3/production/gate_warden/gate_warden_death.png new file mode 100644 index 0000000..212ac81 Binary files /dev/null and b/assets_v3/production/gate_warden/gate_warden_death.png differ diff --git a/assets_v3/production/gate_warden/gate_warden_death.png.import b/assets_v3/production/gate_warden/gate_warden_death.png.import new file mode 100644 index 0000000..18459fe --- /dev/null +++ b/assets_v3/production/gate_warden/gate_warden_death.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://011owpv7mije" +path="res://.godot/imported/gate_warden_death.png-e0732d48f034c7e2aee1501dfb5d21c3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/gate_warden/gate_warden_death.png" +dest_files=["res://.godot/imported/gate_warden_death.png-e0732d48f034c7e2aee1501dfb5d21c3.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=0 diff --git a/assets_v3/production/gate_warden/gate_warden_hurt.png b/assets_v3/production/gate_warden/gate_warden_hurt.png new file mode 100644 index 0000000..25b9c64 Binary files /dev/null and b/assets_v3/production/gate_warden/gate_warden_hurt.png differ diff --git a/assets_v3/production/gate_warden/gate_warden_hurt.png.import b/assets_v3/production/gate_warden/gate_warden_hurt.png.import new file mode 100644 index 0000000..a2a3ba6 --- /dev/null +++ b/assets_v3/production/gate_warden/gate_warden_hurt.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dk4gkjuhsj2u3" +path="res://.godot/imported/gate_warden_hurt.png-410ae3567370b92addbeaab19d80a99e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/gate_warden/gate_warden_hurt.png" +dest_files=["res://.godot/imported/gate_warden_hurt.png-410ae3567370b92addbeaab19d80a99e.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=0 diff --git a/assets_v3/production/gate_warden/gate_warden_idle.png b/assets_v3/production/gate_warden/gate_warden_idle.png new file mode 100644 index 0000000..95d37b9 Binary files /dev/null and b/assets_v3/production/gate_warden/gate_warden_idle.png differ diff --git a/assets_v3/production/gate_warden/gate_warden_idle.png.import b/assets_v3/production/gate_warden/gate_warden_idle.png.import new file mode 100644 index 0000000..ca55b25 --- /dev/null +++ b/assets_v3/production/gate_warden/gate_warden_idle.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cmaqgxkn77n5x" +path="res://.godot/imported/gate_warden_idle.png-ee79d8fe746ba5ba64d290052f6b1156.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/gate_warden/gate_warden_idle.png" +dest_files=["res://.godot/imported/gate_warden_idle.png-ee79d8fe746ba5ba64d290052f6b1156.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=0 diff --git a/assets_v3/production/gate_warden/gate_warden_walk.png b/assets_v3/production/gate_warden/gate_warden_walk.png new file mode 100644 index 0000000..0ed3e32 Binary files /dev/null and b/assets_v3/production/gate_warden/gate_warden_walk.png differ diff --git a/assets_v3/production/gate_warden/gate_warden_walk.png.import b/assets_v3/production/gate_warden/gate_warden_walk.png.import new file mode 100644 index 0000000..91bfb34 --- /dev/null +++ b/assets_v3/production/gate_warden/gate_warden_walk.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djq6y66nvi3kj" +path="res://.godot/imported/gate_warden_walk.png-6fe07d1a127418be0f40536eb005cd4a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/gate_warden/gate_warden_walk.png" +dest_files=["res://.godot/imported/gate_warden_walk.png-6fe07d1a127418be0f40536eb005cd4a.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=0 diff --git a/assets_v3/production/gate_warden/metadata.md b/assets_v3/production/gate_warden/metadata.md new file mode 100644 index 0000000..a38cfcd --- /dev/null +++ b/assets_v3/production/gate_warden/metadata.md @@ -0,0 +1,10 @@ +# Gate Warden Production Metadata + +- Frame size: `320 x 256` +- Pivot: `160, 248` +- Foot position: `160, 248` +- Lighting: upper-left, approved Art V3 palette +- Import: nearest filtering, no mipmaps, lossless RGBA +- Baseline policy: all frames are bottom-anchored; death collapse retains the first death frame scale. + +Animation timing and combat event frames are recorded in `frame_map.json`. diff --git a/assets_v3/production/ghost_archer/frame_map.json b/assets_v3/production/ghost_archer/frame_map.json new file mode 100644 index 0000000..09d43be --- /dev/null +++ b/assets_v3/production/ghost_archer/frame_map.json @@ -0,0 +1,44 @@ +{ + "character": "ghost_archer", + "frame_size": [ + 192, + 160 + ], + "pivot": [ + 96, + 150 + ], + "foot_position": [ + 96, + 150 + ], + "animations": { + "idle": { + "frames": 4, + "fps": 6, + "loop": true + }, + "walk": { + "frames": 6, + "fps": 9, + "loop": true + }, + "attack": { + "frames": 4, + "fps": 10, + "loop": false, + "projectile_frame": 2, + "recovery_frame": 3 + }, + "hurt": { + "frames": 2, + "fps": 8, + "loop": false + }, + "death": { + "frames": 4, + "fps": 7, + "loop": false + } + } +} diff --git a/assets_v3/production/ghost_archer/ghost_archer_attack.png b/assets_v3/production/ghost_archer/ghost_archer_attack.png new file mode 100644 index 0000000..e418cd3 Binary files /dev/null and b/assets_v3/production/ghost_archer/ghost_archer_attack.png differ diff --git a/assets_v3/production/ghost_archer/ghost_archer_attack.png.import b/assets_v3/production/ghost_archer/ghost_archer_attack.png.import new file mode 100644 index 0000000..6f28dbf --- /dev/null +++ b/assets_v3/production/ghost_archer/ghost_archer_attack.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctl608jtlosdt" +path="res://.godot/imported/ghost_archer_attack.png-2009565cc81537a91cbf02fe74efc2b8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_archer/ghost_archer_attack.png" +dest_files=["res://.godot/imported/ghost_archer_attack.png-2009565cc81537a91cbf02fe74efc2b8.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=0 diff --git a/assets_v3/production/ghost_archer/ghost_archer_death.png b/assets_v3/production/ghost_archer/ghost_archer_death.png new file mode 100644 index 0000000..e137355 Binary files /dev/null and b/assets_v3/production/ghost_archer/ghost_archer_death.png differ diff --git a/assets_v3/production/ghost_archer/ghost_archer_death.png.import b/assets_v3/production/ghost_archer/ghost_archer_death.png.import new file mode 100644 index 0000000..3d00f47 --- /dev/null +++ b/assets_v3/production/ghost_archer/ghost_archer_death.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcwymldqb21bl" +path="res://.godot/imported/ghost_archer_death.png-f7ba11fb1b25f3569da90a5111296328.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_archer/ghost_archer_death.png" +dest_files=["res://.godot/imported/ghost_archer_death.png-f7ba11fb1b25f3569da90a5111296328.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=0 diff --git a/assets_v3/production/ghost_archer/ghost_archer_hurt.png b/assets_v3/production/ghost_archer/ghost_archer_hurt.png new file mode 100644 index 0000000..fdaecb1 Binary files /dev/null and b/assets_v3/production/ghost_archer/ghost_archer_hurt.png differ diff --git a/assets_v3/production/ghost_archer/ghost_archer_hurt.png.import b/assets_v3/production/ghost_archer/ghost_archer_hurt.png.import new file mode 100644 index 0000000..a4bf81c --- /dev/null +++ b/assets_v3/production/ghost_archer/ghost_archer_hurt.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cwg02ipirchtc" +path="res://.godot/imported/ghost_archer_hurt.png-f68502ca8f8018de6d0e259af4a6201c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_archer/ghost_archer_hurt.png" +dest_files=["res://.godot/imported/ghost_archer_hurt.png-f68502ca8f8018de6d0e259af4a6201c.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=0 diff --git a/assets_v3/production/ghost_archer/ghost_archer_idle.png b/assets_v3/production/ghost_archer/ghost_archer_idle.png new file mode 100644 index 0000000..a6ffa87 Binary files /dev/null and b/assets_v3/production/ghost_archer/ghost_archer_idle.png differ diff --git a/assets_v3/production/ghost_archer/ghost_archer_idle.png.import b/assets_v3/production/ghost_archer/ghost_archer_idle.png.import new file mode 100644 index 0000000..0918d73 --- /dev/null +++ b/assets_v3/production/ghost_archer/ghost_archer_idle.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfhqxmdm8kjsh" +path="res://.godot/imported/ghost_archer_idle.png-31ea36e3fa513fad5ccd4e3a10229906.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_archer/ghost_archer_idle.png" +dest_files=["res://.godot/imported/ghost_archer_idle.png-31ea36e3fa513fad5ccd4e3a10229906.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=0 diff --git a/assets_v3/production/ghost_archer/ghost_archer_walk.png b/assets_v3/production/ghost_archer/ghost_archer_walk.png new file mode 100644 index 0000000..a4e0985 Binary files /dev/null and b/assets_v3/production/ghost_archer/ghost_archer_walk.png differ diff --git a/assets_v3/production/ghost_archer/ghost_archer_walk.png.import b/assets_v3/production/ghost_archer/ghost_archer_walk.png.import new file mode 100644 index 0000000..ab4f745 --- /dev/null +++ b/assets_v3/production/ghost_archer/ghost_archer_walk.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bic3m34llao43" +path="res://.godot/imported/ghost_archer_walk.png-bbbbc6f7b3772ed6019e020a44fcd5bf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_archer/ghost_archer_walk.png" +dest_files=["res://.godot/imported/ghost_archer_walk.png-bbbbc6f7b3772ed6019e020a44fcd5bf.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=0 diff --git a/assets_v3/production/ghost_archer/metadata.md b/assets_v3/production/ghost_archer/metadata.md new file mode 100644 index 0000000..dcb33cf --- /dev/null +++ b/assets_v3/production/ghost_archer/metadata.md @@ -0,0 +1,10 @@ +# Ghost Archer Production Metadata + +- Frame size: `192 x 160` +- Pivot: `96, 150` +- Foot position: `96, 150` +- Lighting: upper-left, approved Art V3 palette +- Import: nearest filtering, no mipmaps, lossless RGBA +- Baseline policy: all frames are bottom-anchored; death collapse retains the first death frame scale. + +Animation timing and combat event frames are recorded in `frame_map.json`. diff --git a/assets_v3/production/ghost_melee/frame_map.json b/assets_v3/production/ghost_melee/frame_map.json new file mode 100644 index 0000000..090df3f --- /dev/null +++ b/assets_v3/production/ghost_melee/frame_map.json @@ -0,0 +1,44 @@ +{ + "character": "ghost_melee", + "frame_size": [ + 192, + 160 + ], + "pivot": [ + 96, + 150 + ], + "foot_position": [ + 96, + 150 + ], + "animations": { + "idle": { + "frames": 4, + "fps": 6, + "loop": true + }, + "walk": { + "frames": 6, + "fps": 9, + "loop": true + }, + "attack": { + "frames": 4, + "fps": 10, + "loop": false, + "hit_frame": 2, + "recovery_frame": 3 + }, + "hurt": { + "frames": 2, + "fps": 8, + "loop": false + }, + "death": { + "frames": 4, + "fps": 7, + "loop": false + } + } +} diff --git a/assets_v3/production/ghost_melee/ghost_melee_attack.png b/assets_v3/production/ghost_melee/ghost_melee_attack.png new file mode 100644 index 0000000..aa11733 Binary files /dev/null and b/assets_v3/production/ghost_melee/ghost_melee_attack.png differ diff --git a/assets_v3/production/ghost_melee/ghost_melee_attack.png.import b/assets_v3/production/ghost_melee/ghost_melee_attack.png.import new file mode 100644 index 0000000..906557b --- /dev/null +++ b/assets_v3/production/ghost_melee/ghost_melee_attack.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsr8h18tm0nic" +path="res://.godot/imported/ghost_melee_attack.png-d669d87fca75e271486b40334ae94d83.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_melee/ghost_melee_attack.png" +dest_files=["res://.godot/imported/ghost_melee_attack.png-d669d87fca75e271486b40334ae94d83.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=0 diff --git a/assets_v3/production/ghost_melee/ghost_melee_death.png b/assets_v3/production/ghost_melee/ghost_melee_death.png new file mode 100644 index 0000000..2b24a6a Binary files /dev/null and b/assets_v3/production/ghost_melee/ghost_melee_death.png differ diff --git a/assets_v3/production/ghost_melee/ghost_melee_death.png.import b/assets_v3/production/ghost_melee/ghost_melee_death.png.import new file mode 100644 index 0000000..703f62c --- /dev/null +++ b/assets_v3/production/ghost_melee/ghost_melee_death.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dg71ewe7gx242" +path="res://.godot/imported/ghost_melee_death.png-e625f932b18f3d7cc82c000f079b184a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_melee/ghost_melee_death.png" +dest_files=["res://.godot/imported/ghost_melee_death.png-e625f932b18f3d7cc82c000f079b184a.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=0 diff --git a/assets_v3/production/ghost_melee/ghost_melee_hurt.png b/assets_v3/production/ghost_melee/ghost_melee_hurt.png new file mode 100644 index 0000000..2b44b82 Binary files /dev/null and b/assets_v3/production/ghost_melee/ghost_melee_hurt.png differ diff --git a/assets_v3/production/ghost_melee/ghost_melee_hurt.png.import b/assets_v3/production/ghost_melee/ghost_melee_hurt.png.import new file mode 100644 index 0000000..2c6391b --- /dev/null +++ b/assets_v3/production/ghost_melee/ghost_melee_hurt.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dux3bbfc8fu8x" +path="res://.godot/imported/ghost_melee_hurt.png-04b5475f4fba9ae5184f9a422248ed54.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_melee/ghost_melee_hurt.png" +dest_files=["res://.godot/imported/ghost_melee_hurt.png-04b5475f4fba9ae5184f9a422248ed54.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=0 diff --git a/assets_v3/production/ghost_melee/ghost_melee_idle.png b/assets_v3/production/ghost_melee/ghost_melee_idle.png new file mode 100644 index 0000000..585a332 Binary files /dev/null and b/assets_v3/production/ghost_melee/ghost_melee_idle.png differ diff --git a/assets_v3/production/ghost_melee/ghost_melee_idle.png.import b/assets_v3/production/ghost_melee/ghost_melee_idle.png.import new file mode 100644 index 0000000..c3d04fa --- /dev/null +++ b/assets_v3/production/ghost_melee/ghost_melee_idle.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhyvrny13qw78" +path="res://.godot/imported/ghost_melee_idle.png-3d07bc306047361c396946a1a166d68a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_melee/ghost_melee_idle.png" +dest_files=["res://.godot/imported/ghost_melee_idle.png-3d07bc306047361c396946a1a166d68a.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=0 diff --git a/assets_v3/production/ghost_melee/ghost_melee_walk.png b/assets_v3/production/ghost_melee/ghost_melee_walk.png new file mode 100644 index 0000000..4d6ab16 Binary files /dev/null and b/assets_v3/production/ghost_melee/ghost_melee_walk.png differ diff --git a/assets_v3/production/ghost_melee/ghost_melee_walk.png.import b/assets_v3/production/ghost_melee/ghost_melee_walk.png.import new file mode 100644 index 0000000..0f3a59c --- /dev/null +++ b/assets_v3/production/ghost_melee/ghost_melee_walk.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c25n3ew2tcq6l" +path="res://.godot/imported/ghost_melee_walk.png-addda1b5f55150fd0ff6647343dfe25a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/ghost_melee/ghost_melee_walk.png" +dest_files=["res://.godot/imported/ghost_melee_walk.png-addda1b5f55150fd0ff6647343dfe25a.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=0 diff --git a/assets_v3/production/ghost_melee/metadata.md b/assets_v3/production/ghost_melee/metadata.md new file mode 100644 index 0000000..127f928 --- /dev/null +++ b/assets_v3/production/ghost_melee/metadata.md @@ -0,0 +1,10 @@ +# Ghost Melee Production Metadata + +- Frame size: `192 x 160` +- Pivot: `96, 150` +- Foot position: `96, 150` +- Lighting: upper-left, approved Art V3 palette +- Import: nearest filtering, no mipmaps, lossless RGBA +- Baseline policy: all frames are bottom-anchored; death collapse retains the first death frame scale. + +Animation timing and combat event frames are recorded in `frame_map.json`. diff --git a/assets_v3/production/icons/icon_boss.png b/assets_v3/production/icons/icon_boss.png new file mode 100644 index 0000000..a3091fe Binary files /dev/null and b/assets_v3/production/icons/icon_boss.png differ diff --git a/assets_v3/production/icons/icon_boss.png.import b/assets_v3/production/icons/icon_boss.png.import new file mode 100644 index 0000000..65578a7 --- /dev/null +++ b/assets_v3/production/icons/icon_boss.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bejko51pxn66h" +path="res://.godot/imported/icon_boss.png-797efa7025c72e1011a791205031df87.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/icons/icon_boss.png" +dest_files=["res://.godot/imported/icon_boss.png-797efa7025c72e1011a791205031df87.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=0 diff --git a/assets_v3/production/icons/icon_hp.png b/assets_v3/production/icons/icon_hp.png new file mode 100644 index 0000000..3198126 Binary files /dev/null and b/assets_v3/production/icons/icon_hp.png differ diff --git a/assets_v3/production/icons/icon_hp.png.import b/assets_v3/production/icons/icon_hp.png.import new file mode 100644 index 0000000..638c7be --- /dev/null +++ b/assets_v3/production/icons/icon_hp.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b448r6tovffye" +path="res://.godot/imported/icon_hp.png-9a4200f0fb11ed082469895ca562a371.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/icons/icon_hp.png" +dest_files=["res://.godot/imported/icon_hp.png-9a4200f0fb11ed082469895ca562a371.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=0 diff --git a/assets_v3/production/icons/icon_sacrifice.png b/assets_v3/production/icons/icon_sacrifice.png new file mode 100644 index 0000000..ad583e0 Binary files /dev/null and b/assets_v3/production/icons/icon_sacrifice.png differ diff --git a/assets_v3/production/icons/icon_sacrifice.png.import b/assets_v3/production/icons/icon_sacrifice.png.import new file mode 100644 index 0000000..3951053 --- /dev/null +++ b/assets_v3/production/icons/icon_sacrifice.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1cyk07uhkils" +path="res://.godot/imported/icon_sacrifice.png-cf8fce7a0c82f337513b539cc3516baf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/icons/icon_sacrifice.png" +dest_files=["res://.godot/imported/icon_sacrifice.png-cf8fce7a0c82f337513b539cc3516baf.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=0 diff --git a/assets_v3/production/icons/metadata.md b/assets_v3/production/icons/metadata.md new file mode 100644 index 0000000..30084a9 --- /dev/null +++ b/assets_v3/production/icons/metadata.md @@ -0,0 +1,3 @@ +# UI Icon Metadata + +64 x 64 transparent RGBA icons, nearest-filtered, approved Art V3 palette and upper-left lighting. diff --git a/assets_v3/production/player/frame_map.json b/assets_v3/production/player/frame_map.json new file mode 100644 index 0000000..e4a9c32 --- /dev/null +++ b/assets_v3/production/player/frame_map.json @@ -0,0 +1,44 @@ +{ + "character": "player", + "frame_size": [ + 192, + 160 + ], + "pivot": [ + 96, + 150 + ], + "foot_position": [ + 96, + 150 + ], + "animations": { + "idle": { + "frames": 4, + "fps": 6, + "loop": true + }, + "walk": { + "frames": 6, + "fps": 10, + "loop": true + }, + "attack": { + "frames": 4, + "fps": 12, + "loop": false, + "hit_frame": 2, + "recovery_frame": 3 + }, + "hurt": { + "frames": 2, + "fps": 8, + "loop": false + }, + "death": { + "frames": 6, + "fps": 8, + "loop": false + } + } +} diff --git a/assets_v3/production/player/metadata.md b/assets_v3/production/player/metadata.md new file mode 100644 index 0000000..aae92c4 --- /dev/null +++ b/assets_v3/production/player/metadata.md @@ -0,0 +1,10 @@ +# Player Production Metadata + +- Frame size: `192 x 160` +- Pivot: `96, 150` +- Foot position: `96, 150` +- Lighting: upper-left, approved Art V3 palette +- Import: nearest filtering, no mipmaps, lossless RGBA +- Baseline policy: all frames are bottom-anchored; death collapse retains the first death frame scale. + +Animation timing and combat event frames are recorded in `frame_map.json`. diff --git a/assets_v3/production/player/player_attack.png b/assets_v3/production/player/player_attack.png new file mode 100644 index 0000000..4c56731 Binary files /dev/null and b/assets_v3/production/player/player_attack.png differ diff --git a/assets_v3/production/player/player_attack.png.import b/assets_v3/production/player/player_attack.png.import new file mode 100644 index 0000000..98f4fcf --- /dev/null +++ b/assets_v3/production/player/player_attack.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwdkhjn6uw56x" +path="res://.godot/imported/player_attack.png-a3de0d5de5ad3c81f6b459c2ffe05c58.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/player/player_attack.png" +dest_files=["res://.godot/imported/player_attack.png-a3de0d5de5ad3c81f6b459c2ffe05c58.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=0 diff --git a/assets_v3/production/player/player_death.png b/assets_v3/production/player/player_death.png new file mode 100644 index 0000000..22d562e Binary files /dev/null and b/assets_v3/production/player/player_death.png differ diff --git a/assets_v3/production/player/player_death.png.import b/assets_v3/production/player/player_death.png.import new file mode 100644 index 0000000..56637ce --- /dev/null +++ b/assets_v3/production/player/player_death.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dklwvlfvcebiq" +path="res://.godot/imported/player_death.png-b4d3dff26ba7290d5b64e74f13471bc7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/player/player_death.png" +dest_files=["res://.godot/imported/player_death.png-b4d3dff26ba7290d5b64e74f13471bc7.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=0 diff --git a/assets_v3/production/player/player_hurt.png b/assets_v3/production/player/player_hurt.png new file mode 100644 index 0000000..9cdfaaf Binary files /dev/null and b/assets_v3/production/player/player_hurt.png differ diff --git a/assets_v3/production/player/player_hurt.png.import b/assets_v3/production/player/player_hurt.png.import new file mode 100644 index 0000000..cb4e3f9 --- /dev/null +++ b/assets_v3/production/player/player_hurt.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfq3su7atvyd6" +path="res://.godot/imported/player_hurt.png-b09c628a2527f1d3055d13fa30bc3277.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/player/player_hurt.png" +dest_files=["res://.godot/imported/player_hurt.png-b09c628a2527f1d3055d13fa30bc3277.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=0 diff --git a/assets_v3/production/player/player_idle.png b/assets_v3/production/player/player_idle.png new file mode 100644 index 0000000..b03c573 Binary files /dev/null and b/assets_v3/production/player/player_idle.png differ diff --git a/assets_v3/production/player/player_idle.png.import b/assets_v3/production/player/player_idle.png.import new file mode 100644 index 0000000..bc14732 --- /dev/null +++ b/assets_v3/production/player/player_idle.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j0tmq4ohfnw2" +path="res://.godot/imported/player_idle.png-278a2a25fe760ba4484a4d84144ed7d6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/player/player_idle.png" +dest_files=["res://.godot/imported/player_idle.png-278a2a25fe760ba4484a4d84144ed7d6.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=0 diff --git a/assets_v3/production/player/player_walk.png b/assets_v3/production/player/player_walk.png new file mode 100644 index 0000000..22f10d2 Binary files /dev/null and b/assets_v3/production/player/player_walk.png differ diff --git a/assets_v3/production/player/player_walk.png.import b/assets_v3/production/player/player_walk.png.import new file mode 100644 index 0000000..33c2345 --- /dev/null +++ b/assets_v3/production/player/player_walk.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6cso1faiwlv7" +path="res://.godot/imported/player_walk.png-3553be4953e1658cd1a11682f28d521c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/player/player_walk.png" +dest_files=["res://.godot/imported/player_walk.png-3553be4953e1658cd1a11682f28d521c.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=0 diff --git a/assets_v3/production/projectiles/ghost_arrow.png b/assets_v3/production/projectiles/ghost_arrow.png new file mode 100644 index 0000000..99c3371 Binary files /dev/null and b/assets_v3/production/projectiles/ghost_arrow.png differ diff --git a/assets_v3/production/projectiles/ghost_arrow.png.import b/assets_v3/production/projectiles/ghost_arrow.png.import new file mode 100644 index 0000000..8b5c8a8 --- /dev/null +++ b/assets_v3/production/projectiles/ghost_arrow.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwqnsiwby24hp" +path="res://.godot/imported/ghost_arrow.png-5f06493a8e3c0a8718382ef6f3574a5e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/projectiles/ghost_arrow.png" +dest_files=["res://.godot/imported/ghost_arrow.png-5f06493a8e3c0a8718382ef6f3574a5e.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=0 diff --git a/assets_v3/production/projectiles/metadata.md b/assets_v3/production/projectiles/metadata.md new file mode 100644 index 0000000..354d306 --- /dev/null +++ b/assets_v3/production/projectiles/metadata.md @@ -0,0 +1,5 @@ +# Ghost Arrow Metadata + +- Size: `32 x 8` +- Pivot: `16, 4` +- Transparent RGBA; authored facing right; no animation, homing, or spread. diff --git a/assets_v3/production/source/README.md b/assets_v3/production/source/README.md new file mode 100644 index 0000000..ed34898 --- /dev/null +++ b/assets_v3/production/source/README.md @@ -0,0 +1,24 @@ +# Art V3 Production Source Boards + +These transparent RGBA boards are the retained inputs for +`assets_v3/tools/build_production_assets.py`. They were generated with the +built-in image-generation workflow using only +`assets_v3/review/character_lineup.png` as the visual reference, then processed +from a flat `#FF00FF` chroma field to alpha. + +Prompt set: + +- Player: approved lineup identity; idle 4, walk 6, attack 4, hurt 2, death 6. +- Ghost Melee: approved lineup identity; idle, walk, attack, hurt, death only. +- Ghost Archer: approved lineup identity; idle, walk, bow attack, hurt, death only. +- Gate Warden: approved mounted identity; idle, walk, attack, hurt, death only. +- Environment: stone floor, fortress wall, fortress gate only. +- Effects: slash, hit, blood, ghost fire, death dissolve only. +- Icons: HP seal, Gate Warden Boss mark, sacrifice talisman only. + +All prompts required production sprite isolation, consistent approved palette +and upper-left lighting, crisp pixel edges, wide gutters, no labels, no new +armour or character reinterpretation, and no unapproved animations. + +Do not use the master-board crop bounds directly in Godot. The normalized +strips under the sibling production directories are the runtime deliverables. diff --git a/assets_v3/production/source/effects_master.png b/assets_v3/production/source/effects_master.png new file mode 100644 index 0000000..5beb691 Binary files /dev/null and b/assets_v3/production/source/effects_master.png differ diff --git a/assets_v3/production/source/effects_master.png.import b/assets_v3/production/source/effects_master.png.import new file mode 100644 index 0000000..6392cd7 --- /dev/null +++ b/assets_v3/production/source/effects_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brwe87eift8xw" +path="res://.godot/imported/effects_master.png-0a2b6e3e876bebc2f695220d6643a3ab.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/effects_master.png" +dest_files=["res://.godot/imported/effects_master.png-0a2b6e3e876bebc2f695220d6643a3ab.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=0 diff --git a/assets_v3/production/source/environment_master.png b/assets_v3/production/source/environment_master.png new file mode 100644 index 0000000..e8b348a Binary files /dev/null and b/assets_v3/production/source/environment_master.png differ diff --git a/assets_v3/production/source/environment_master.png.import b/assets_v3/production/source/environment_master.png.import new file mode 100644 index 0000000..2ddb5b0 --- /dev/null +++ b/assets_v3/production/source/environment_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dapwqjlkwukx2" +path="res://.godot/imported/environment_master.png-8af5c4b2c9c2bb6277566e77fcbf7551.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/environment_master.png" +dest_files=["res://.godot/imported/environment_master.png-8af5c4b2c9c2bb6277566e77fcbf7551.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=0 diff --git a/assets_v3/production/source/gate_warden_master.png b/assets_v3/production/source/gate_warden_master.png new file mode 100644 index 0000000..1637c14 Binary files /dev/null and b/assets_v3/production/source/gate_warden_master.png differ diff --git a/assets_v3/production/source/gate_warden_master.png.import b/assets_v3/production/source/gate_warden_master.png.import new file mode 100644 index 0000000..7ba11dc --- /dev/null +++ b/assets_v3/production/source/gate_warden_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1n2fiu33veak" +path="res://.godot/imported/gate_warden_master.png-057370e1295f3dd79b7bf54dd8916d76.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/gate_warden_master.png" +dest_files=["res://.godot/imported/gate_warden_master.png-057370e1295f3dd79b7bf54dd8916d76.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=0 diff --git a/assets_v3/production/source/ghost_archer_master.png b/assets_v3/production/source/ghost_archer_master.png new file mode 100644 index 0000000..be2bd2f Binary files /dev/null and b/assets_v3/production/source/ghost_archer_master.png differ diff --git a/assets_v3/production/source/ghost_archer_master.png.import b/assets_v3/production/source/ghost_archer_master.png.import new file mode 100644 index 0000000..9928a7f --- /dev/null +++ b/assets_v3/production/source/ghost_archer_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bfdcgnjqqsaqg" +path="res://.godot/imported/ghost_archer_master.png-22c6f2d7ff0a21b856385ecac0cbaf55.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/ghost_archer_master.png" +dest_files=["res://.godot/imported/ghost_archer_master.png-22c6f2d7ff0a21b856385ecac0cbaf55.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=0 diff --git a/assets_v3/production/source/ghost_melee_master.png b/assets_v3/production/source/ghost_melee_master.png new file mode 100644 index 0000000..f60f0c1 Binary files /dev/null and b/assets_v3/production/source/ghost_melee_master.png differ diff --git a/assets_v3/production/source/ghost_melee_master.png.import b/assets_v3/production/source/ghost_melee_master.png.import new file mode 100644 index 0000000..ef89290 --- /dev/null +++ b/assets_v3/production/source/ghost_melee_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://855aj48jyipb" +path="res://.godot/imported/ghost_melee_master.png-4bf2c6c5cf6f87515fe5fe7a50962cf1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/ghost_melee_master.png" +dest_files=["res://.godot/imported/ghost_melee_master.png-4bf2c6c5cf6f87515fe5fe7a50962cf1.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=0 diff --git a/assets_v3/production/source/icons_master.png b/assets_v3/production/source/icons_master.png new file mode 100644 index 0000000..a68315b Binary files /dev/null and b/assets_v3/production/source/icons_master.png differ diff --git a/assets_v3/production/source/icons_master.png.import b/assets_v3/production/source/icons_master.png.import new file mode 100644 index 0000000..3c0110b --- /dev/null +++ b/assets_v3/production/source/icons_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d24nch4qoar8e" +path="res://.godot/imported/icons_master.png-20a939aeafd3d79675f6804cb59ffc1e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/icons_master.png" +dest_files=["res://.godot/imported/icons_master.png-20a939aeafd3d79675f6804cb59ffc1e.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=0 diff --git a/assets_v3/production/source/player_master.png b/assets_v3/production/source/player_master.png new file mode 100644 index 0000000..d778909 Binary files /dev/null and b/assets_v3/production/source/player_master.png differ diff --git a/assets_v3/production/source/player_master.png.import b/assets_v3/production/source/player_master.png.import new file mode 100644 index 0000000..a89a46e --- /dev/null +++ b/assets_v3/production/source/player_master.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b47uvvbuyu4lo" +path="res://.godot/imported/player_master.png-f68e616eeb7087ac981d714fdc97aa07.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/production/source/player_master.png" +dest_files=["res://.godot/imported/player_master.png-f68e616eeb7087ac981d714fdc97aa07.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=0 diff --git a/assets_v3/review/character_lineup.png.import b/assets_v3/review/character_lineup.png.import new file mode 100644 index 0000000..59daa6c --- /dev/null +++ b/assets_v3/review/character_lineup.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bee2lgm1n1j0d" +path="res://.godot/imported/character_lineup.png-66d7bc8f5dd2b595ce3dee7993941c3b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/review/character_lineup.png" +dest_files=["res://.godot/imported/character_lineup.png-66d7bc8f5dd2b595ce3dee7993941c3b.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=0 diff --git a/assets_v3/review/scale_reference.png.import b/assets_v3/review/scale_reference.png.import new file mode 100644 index 0000000..499d7a6 --- /dev/null +++ b/assets_v3/review/scale_reference.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b5ajw0s0v6812" +path="res://.godot/imported/scale_reference.png-9f5f0be9ddc907f81263ec234cae0d8f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/review/scale_reference.png" +dest_files=["res://.godot/imported/scale_reference.png-9f5f0be9ddc907f81263ec234cae0d8f.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=0 diff --git a/assets_v3/review/silhouette_test.png.import b/assets_v3/review/silhouette_test.png.import new file mode 100644 index 0000000..d7edcfe --- /dev/null +++ b/assets_v3/review/silhouette_test.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dcnl2nxq0ew2b" +path="res://.godot/imported/silhouette_test.png-a650826e3ac71f97273b4e671be6dbcf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets_v3/review/silhouette_test.png" +dest_files=["res://.godot/imported/silhouette_test.png-a650826e3ac71f97273b4e671be6dbcf.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=0 diff --git a/assets_v3/tools/build_production_assets.py b/assets_v3/tools/build_production_assets.py new file mode 100644 index 0000000..97f4d54 --- /dev/null +++ b/assets_v3/tools/build_production_assets.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 +"""Build Godot-ready Art V3 assets from the approved production master sheets. + +The source sheets are already chroma-keyed to RGBA. This script only performs +deterministic cropping, nearest-neighbour pixel scaling, foot-baseline +normalisation, strip assembly, and metadata generation. +""" + +from __future__ import annotations + +import json +from pathlib import Path + +from PIL import Image + + +ROOT = Path(__file__).resolve().parents[2] +SOURCE = ROOT / "assets_v3" / "production" / "source" +OUTPUT = ROOT / "assets_v3" / "production" + +ANIMATIONS = ("idle", "walk", "attack", "hurt", "death") + + +CHARACTERS = { + "player": { + "source": "player_master.png", + "frame_size": (192, 160), + "foot_y": 150, + "target_height": 144, + "fps": {"idle": 6, "walk": 10, "attack": 12, "hurt": 8, "death": 8}, + "rows": { + "idle": ((18, 202), [(36, 163), (224, 351), (412, 539), (602, 731)]), + "walk": ((221, 397), [(49, 174), (238, 370), (418, 554), (622, 732), (801, 917), (1026, 1127)]), + "attack": ((421, 595), [(33, 154), (246, 389), (449, 633), (670, 856)]), + "hurt": ((614, 747), [(33, 171), (250, 387)]), + "death": ((771, 905), [(40, 152), (264, 380), (459, 611), (690, 868), (938, 1111), (1181, 1354)]), + }, + "events": {"attack": {"hit_frame": 2, "recovery_frame": 3}}, + }, + "ghost_melee": { + "source": "ghost_melee_master.png", + "frame_size": (192, 160), + "foot_y": 150, + "target_height": 144, + "fps": {"idle": 6, "walk": 9, "attack": 10, "hurt": 8, "death": 7}, + "rows": { + # The approved board contains three unique idle poses. The first is + # repeated to retain the framework's four-frame idle timing. + "idle": ((19, 236), [(104, 246), (314, 455), (524, 665), (524, 665)]), + "walk": ((250, 464), [(111, 270), (332, 491), (549, 696), (784, 941), (1010, 1166), (1223, 1381)]), + "attack": ((473, 675), [(131, 330), (438, 561), (657, 900), (1002, 1184)]), + "hurt": ((688, 856), [(150, 292), (396, 524)]), + "death": ((869, 995), [(127, 308), (389, 612), (697, 979), (1027, 1289)]), + }, + "events": {"attack": {"hit_frame": 2, "recovery_frame": 3}}, + }, + "ghost_archer": { + "source": "ghost_archer_master.png", + "frame_size": (192, 160), + "foot_y": 150, + "target_height": 144, + "fps": {"idle": 6, "walk": 9, "attack": 10, "hurt": 8, "death": 7}, + "rows": { + "idle": ((47, 373), [(42, 220), (266, 444), (490, 667), (697, 875)]), + "walk": ((424, 686), [(16, 143), (180, 307), (347, 479), (523, 657), (691, 817), (860, 989)]), + "attack": ((733, 1028), [(16, 184), (253, 422), (449, 696), (795, 962)]), + "hurt": ((1069, 1279), [(46, 165), (257, 386)]), + "death": ((1332, 1487), [(43, 189), (284, 456), (531, 715), (787, 1001)]), + }, + "events": {"attack": {"projectile_frame": 2, "recovery_frame": 3}}, + }, + "gate_warden": { + "source": "gate_warden_master.png", + "frame_size": (320, 256), + "foot_y": 248, + "target_height": 236, + "fps": {"idle": 5, "walk": 7, "attack": 9, "hurt": 7, "death": 6}, + "rows": { + "idle": ((10, 221), [(175, 354), (365, 543), (550, 720), (550, 720)]), + "walk": ((221, 418), [(170, 350), (360, 540), (550, 720), (725, 910), (915, 1110), (1115, 1310)]), + "attack": ((418, 630), [(150, 350), (350, 575), (575, 815), (815, 1055), (1055, 1280)]), + "hurt": ((630, 805), [(135, 315), (315, 625)]), + # Seven unique collapse poses are present; repeat the settled final + # pose so the existing eight-frame death timing remains unchanged. + "death": ((805, 952), [(20, 270), (285, 520), (535, 750), (760, 1000), (995, 1220), (1210, 1430), (1420, 1652), (1420, 1652)]), + }, + "events": {"attack": {"hit_frame": 2, "recovery_frame": 4}}, + }, +} + + +EFFECTS = { + "slash": ((86, 183), [(132, 324), (477, 702), (829, 1076), (1183, 1435)], (96, 64), 12), + "hit": ((267, 369), [(192, 293), (528, 637), (905, 1009), (1240, 1360)], (64, 64), 16), + "blood": ((448, 538), [(126, 349), (496, 709), (866, 1046), (1198, 1367)], (96, 64), 14), + "ghost_fire": ((602, 734), [(176, 241), (404, 471), (632, 700), (863, 928), (1090, 1154), (1312, 1380)], (64, 64), 10), + "death": ((793, 946), [(166, 251), (394, 481), (622, 709), (849, 937), (1080, 1164), (1304, 1392)], (64, 80), 10), +} + + +def alpha_bbox(image: Image.Image) -> tuple[int, int, int, int]: + bbox = image.getchannel("A").getbbox() + if bbox is None: + raise ValueError("Frame contains no visible pixels") + return bbox + + +def crop_frame(master: Image.Image, y_range: tuple[int, int], x_range: tuple[int, int]) -> Image.Image: + frame = master.crop((x_range[0], y_range[0], x_range[1], y_range[1])) + return frame.crop(alpha_bbox(frame)) + + +def place_frame(frame: Image.Image, size: tuple[int, int], scale: float, baseline: int) -> Image.Image: + width = max(1, round(frame.width * scale)) + height = max(1, round(frame.height * scale)) + if width > size[0] - 4: + fit = (size[0] - 4) / width + width = max(1, round(width * fit)) + height = max(1, round(height * fit)) + resized = frame.resize((width, height), Image.Resampling.NEAREST) + canvas = Image.new("RGBA", size) + x = (size[0] - width) // 2 + y = baseline - height + canvas.alpha_composite(resized, (x, y)) + # Nearest-neighbour reduction can discard a sparse final alpha row. Measure + # the composed result and snap its actual lowest visible pixel to baseline. + visible = alpha_bbox(canvas) + if visible[3] != baseline: + snapped = Image.new("RGBA", size) + snapped.alpha_composite(canvas, (0, baseline - visible[3])) + canvas = snapped + return canvas + + +def write_strip(path: Path, frames: list[Image.Image], frame_size: tuple[int, int]) -> None: + strip = Image.new("RGBA", (frame_size[0] * len(frames), frame_size[1])) + for index, frame in enumerate(frames): + strip.alpha_composite(frame, (index * frame_size[0], 0)) + path.parent.mkdir(parents=True, exist_ok=True) + strip.save(path, optimize=True) + + +def build_characters() -> None: + for character, spec in CHARACTERS.items(): + master = Image.open(SOURCE / spec["source"]).convert("RGBA") + destination = OUTPUT / character + frame_map: dict[str, object] = { + "character": character, + "frame_size": list(spec["frame_size"]), + "pivot": [spec["frame_size"][0] // 2, spec["foot_y"]], + "foot_position": [spec["frame_size"][0] // 2, spec["foot_y"]], + "animations": {}, + } + for animation in ANIMATIONS: + y_range, x_ranges = spec["rows"][animation] + crops = [crop_frame(master, y_range, x_range) for x_range in x_ranges] + scale = spec["target_height"] / crops[0].height + frames = [place_frame(crop, spec["frame_size"], scale, spec["foot_y"]) for crop in crops] + write_strip(destination / f"{character}_{animation}.png", frames, spec["frame_size"]) + events = spec.get("events", {}).get(animation, {}) + frame_map["animations"][animation] = { + "frames": len(frames), + "fps": spec["fps"][animation], + "loop": animation in ("idle", "walk"), + **events, + } + destination.mkdir(parents=True, exist_ok=True) + (destination / "frame_map.json").write_text(json.dumps(frame_map, indent=2) + "\n") + (destination / "metadata.md").write_text( + f"# {character.replace('_', ' ').title()} Production Metadata\n\n" + f"- Frame size: `{spec['frame_size'][0]} x {spec['frame_size'][1]}`\n" + f"- Pivot: `{spec['frame_size'][0] // 2}, {spec['foot_y']}`\n" + f"- Foot position: `{spec['frame_size'][0] // 2}, {spec['foot_y']}`\n" + "- Lighting: upper-left, approved Art V3 palette\n" + "- Import: nearest filtering, no mipmaps, lossless RGBA\n" + "- Baseline policy: all frames are bottom-anchored; death collapse retains the first death frame scale.\n\n" + "Animation timing and combat event frames are recorded in `frame_map.json`.\n" + ) + + +def build_effects() -> None: + master = Image.open(SOURCE / "effects_master.png").convert("RGBA") + destination = OUTPUT / "effects" + metadata: dict[str, object] = {"effects": {}} + for name, (y_range, x_ranges, frame_size, fps) in EFFECTS.items(): + crops = [crop_frame(master, y_range, x_range) for x_range in x_ranges] + scale = min((frame_size[0] - 4) / crops[0].width, (frame_size[1] - 4) / crops[0].height) + frames = [place_frame(crop, frame_size, scale, frame_size[1] - 2) for crop in crops] + write_strip(destination / f"{name}.png", frames, frame_size) + metadata["effects"][name] = {"frame_size": list(frame_size), "frames": len(frames), "fps": fps} + destination.mkdir(parents=True, exist_ok=True) + (destination / "frame_map.json").write_text(json.dumps(metadata, indent=2) + "\n") + (destination / "metadata.md").write_text( + "# Combat Effect Metadata\n\n" + "Transparent RGBA pixel effects using the approved Art V3 palette. Frame sizes, counts, and FPS are in `frame_map.json`.\n" + ) + + +def fit_asset(master: Image.Image, box: tuple[int, int, int, int], size: tuple[int, int], baseline: bool = False) -> Image.Image: + crop = master.crop(box) + crop = crop.crop(alpha_bbox(crop)) + scale = min(size[0] / crop.width, size[1] / crop.height) + resized = crop.resize((max(1, round(crop.width * scale)), max(1, round(crop.height * scale))), Image.Resampling.NEAREST) + canvas = Image.new("RGBA", size) + x = (size[0] - resized.width) // 2 + y = size[1] - resized.height if baseline else (size[1] - resized.height) // 2 + canvas.alpha_composite(resized, (x, y)) + return canvas + + +def build_environment_and_icons() -> None: + environment = Image.open(SOURCE / "environment_master.png").convert("RGBA") + env_out = OUTPUT / "environment" + env_out.mkdir(parents=True, exist_ok=True) + fit_asset(environment, (25, 335, 650, 640), (256, 128), True).save(env_out / "stone_floor.png") + fit_asset(environment, (710, 195, 1185, 700), (256, 256), True).save(env_out / "stone_wall.png") + fit_asset(environment, (1230, 95, 1890, 700), (384, 384), True).save(env_out / "fortress_gate.png") + + # Low-resolution deterministic alpha fog: presentation-only, no gameplay data. + fog = Image.new("RGBA", (320, 96)) + pixels = fog.load() + for y in range(fog.height): + for x in range(fog.width): + wave = ((x * 13 + y * 29 + (x // 17) * 31) % 73) / 72.0 + vertical = max(0.0, 1.0 - abs(y - 58) / 48.0) + alpha = round(38 * wave * vertical) + pixels[x, y] = (126, 157, 163, alpha) + fog.save(env_out / "battlefield_fog.png", optimize=True) + + icons = Image.open(SOURCE / "icons_master.png").convert("RGBA") + icon_out = OUTPUT / "icons" + icon_out.mkdir(parents=True, exist_ok=True) + for name, box in { + "icon_hp": (245, 285, 570, 680), + "icon_boss": (785, 145, 1120, 690), + "icon_sacrifice": (1320, 230, 1700, 680), + }.items(): + fit_asset(icons, box, (64, 64)).save(icon_out / f"{name}.png", optimize=True) + (icon_out / "metadata.md").write_text( + "# UI Icon Metadata\n\n64 x 64 transparent RGBA icons, nearest-filtered, approved Art V3 palette and upper-left lighting.\n" + ) + + projectile_out = OUTPUT / "projectiles" + projectile_out.mkdir(parents=True, exist_ok=True) + arrow = Image.new("RGBA", (32, 8)) + px = arrow.load() + # Palette sampled from the approved Ghost Archer: dark iron shaft, aged + # bronze fletching, and a restrained spectral-cyan arrowhead highlight. + for x in range(4, 25): + px[x, 3] = (55, 45, 38, 255) + px[x, 4] = (109, 82, 50, 255) + for x, y in ((1, 1), (2, 2), (3, 3), (1, 6), (2, 5), (3, 4)): + px[x, y] = (123, 76, 49, 255) + for x, y in ((25, 2), (26, 2), (27, 1), (28, 0), (25, 5), (26, 5), (27, 6), (28, 7)): + px[x, y] = (77, 176, 146, 255) + for x in range(25, 31): + px[x, 3] = (177, 226, 187, 255) + px[x, 4] = (91, 201, 164, 255) + arrow.save(projectile_out / "ghost_arrow.png", optimize=True) + (projectile_out / "metadata.md").write_text( + "# Ghost Arrow Metadata\n\n- Size: `32 x 8`\n- Pivot: `16, 4`\n- Transparent RGBA; authored facing right; no animation, homing, or spread.\n" + ) + + +def main() -> None: + build_characters() + build_effects() + build_environment_and_icons() + print(f"Built Art V3 production assets in {OUTPUT}") + + +if __name__ == "__main__": + main() diff --git a/docs/AI_HANDOFF.md b/docs/AI_HANDOFF.md index d647705..50155b4 100644 --- a/docs/AI_HANDOFF.md +++ b/docs/AI_HANDOFF.md @@ -1,16 +1,35 @@ # AI Handoff -- **Current branch:** `codex/m15-art-v2-integration` -- **Current phase:** M1.5 Art V2 integrated; draft PR #6 open for review -- **Next owner:** Claude and Game Director for visual/gameplay review +- **Current branch:** `codex/production-asset-sprint-01` +- **Current phase:** Art V3 production assets integrated on the latest `develop` +- **Next owner:** Game Director for Draft PR #8 review - **Last updated:** 2026-08-02 (Australia/Melbourne) ## Playable status The complete M1 loop remains playable: arena wave → sacrifice → Gate Warden → -victory/defeat → restart. Normal gameplay now renders the production V2 player, -melee ghost, Ghost Archer, Ghost Arrow, Gate Warden, combat effects, and matching -HUD icons. Debug collision shapes remain off by default and available on F8. +victory/defeat → restart. Normal gameplay now renders the approved Art V3 +player, melee ghost, Ghost Archer, Ghost Arrow, Gate Warden, environment, +combat effects, and primary HUD icons. Develop's gameplay architecture, +authored attack timing, collision geometry, and additional HUD statistics are +preserved. Debug collision shapes remain off by default and available on F8. + +## Art V3 production integration + +The V3 production strips are mapped into develop's established animation names +and frame-event contracts. Where a four- or five-pose approved strip is shorter +than develop's authored timing map, source poses are deliberately held across +multiple frames; this preserves startup, active, release, and recovery events +without changing gameplay scripts. Scene-local sprite position and scale keep +each declared V3 foot position on the stable actor origin. Combat feedback uses +the V3 slash, hit, blood, and death sheets, while damage remains exclusively in +`CombatResolver`. + +The merge with current `develop` retained its player, melee ghost, Ghost Archer, +Boss, HUD, result-flow, and debug integration. The hidden Ghost Arrow polygon is +kept only as develop's emergency fallback; normal rendering uses the V3 arrow. +See `docs/PRODUCTION_ASSET_REPLACEMENT.md` and the V3 production `frame_map.json` +files for the replacement inventory and metadata. ## M1.5 integration @@ -65,7 +84,7 @@ actor/state scripts and scenes. ## Tests -- **Local:** 66 tests, 421 assertions, 0 failures +- **Local:** 71 tests, 686 assertions, 0 failures - **Engine:** Godot 4.7.1 stable headless locally; CI remains pinned to 4.3 - **Commands:** - `godot --headless --import` diff --git a/docs/PRODUCTION_ASSET_REPLACEMENT.md b/docs/PRODUCTION_ASSET_REPLACEMENT.md new file mode 100644 index 0000000..da67c01 --- /dev/null +++ b/docs/PRODUCTION_ASSET_REPLACEMENT.md @@ -0,0 +1,112 @@ +# Production Asset Replacement — Sprint 01 + +**Source of truth:** `assets_v3/review/character_lineup.png` +**Branch:** `codex/production-asset-sprint-01` + +This matrix is limited to assets that are instantiated by the current playable +M1 scenes, plus the combat-readability effects explicitly approved for this +sprint. Future characters, attacks, phases, props, inventory art, and weapons +are excluded. + +| Current asset | Scene / consumer | Replacement asset | Priority | +| --- | --- | --- | --- | +| `assets/player/player_idle.png` | `actors/player/player_frames.tres` | `assets_v3/production/player/player_idle.png` | P0 | +| `assets/player/player_run.png` | `actors/player/player_frames.tres` | `assets_v3/production/player/player_walk.png` | P0 | +| `assets/player/player_attack.png` | `actors/player/player_frames.tres` | `assets_v3/production/player/player_attack.png` | P0 | +| `assets/player/player_hurt.png` | `actors/player/player_frames.tres` | `assets_v3/production/player/player_hurt.png` | P0 | +| `assets/player/player_death.png` | `actors/player/player_frames.tres` | `assets_v3/production/player/player_death.png` | P0 | +| `assets/player/player_jump.png` | player jump state | production idle frame reused; no new jump art in Sprint 01 | P0 | +| `assets/enemy/ghost_melee_*` | `actors/enemies/ghost_melee_frames.tres` | `assets_v3/production/ghost_melee/ghost_melee_*.png` | P0 | +| `assets/enemy/ghost_archer_*` | `actors/enemies/ghost_archer_frames.tres` | `assets_v3/production/ghost_archer/ghost_archer_*.png` | P0 | +| `Polygon2D` arrow fallback | `actors/enemies/ghost_arrow.tscn` | `assets_v3/production/projectiles/ghost_arrow.png` | P0 | +| `assets/boss/boss_*` | `actors/boss/boss_frames.tres` | `assets_v3/production/gate_warden/gate_warden_*.png` | P0 | +| `assets/tiles/tile_floor.png` | `scenes/arena.tscn` floor region | `assets_v3/production/environment/stone_floor.png` | P0 | +| `assets/tiles/tile_stone_brick.png` | arena wall/boundary sprites | `assets_v3/production/environment/stone_wall.png` | P0 | +| arena tomb/flag focal prop | `scenes/arena.tscn` | `assets_v3/production/environment/fortress_gate.png` | P1 | +| `assets/background/bg_deep.png`, `bg_tree.png`, `bg_chains.png` | arena parallax | `assets_v3/production/environment/battlefield_fog.png` and retained non-placeholder composition layers | P1 | +| brazier placeholder | `scenes/arena.tscn` | `assets_v3/production/effects/ghost_fire.png` | P1 | +| no production slash feedback | player attack presentation | `assets_v3/production/effects/slash.png` | P1 | +| no confirmed-hit feedback | EventBus observer | `assets_v3/production/effects/hit.png` | P1 | +| no blood feedback | EventBus observer | `assets_v3/production/effects/blood.png` | P1 | +| `assets/effects/effect_death_fade.png` | death presentation | `assets_v3/production/effects/death.png` | P1 | +| `assets/icons/ui/icon_hp.png` | `ui/hud.tscn` | `assets_v3/production/icons/icon_hp.png` | P1 | +| `assets/icons/ui/icon_boss.png` | `ui/hud.tscn` | `assets_v3/production/icons/icon_boss.png` | P1 | +| `assets/icons/ui/icon_sacrifice.png` | `ui/sacrifice_panel.tscn` | `assets_v3/production/icons/icon_sacrifice.png` | P1 | + +## Explicit exclusions + +- Player heavy attack and second light attack +- Gate Warden second phase or special attacks +- Corpse Beast and other future enemies +- Unused tiles, weapon icons, inventory frame, minimap frame, and decorative props +- Any gameplay, balance, state-machine, collision, Hitbox/Hurtbox, or + `CombatResolver` redesign + +## Production output + +All generated deliverables are transparent, lossless RGBA PNGs under +`assets_v3/production/`. The committed `source/` boards have already had the +flat chroma field removed; `assets_v3/tools/build_production_assets.py` +deterministically rebuilds the normalized strips and metadata from them. + +| Group | Delivered | +| --- | --- | +| Player | idle 4, walk 6, attack 4, hurt 2, death 6 | +| Ghost Melee | idle 4, walk 6, attack 4, hurt 2, death 4 | +| Ghost Archer | idle 4, walk 6, attack 4, hurt 2, death 4 | +| Gate Warden | idle 4, walk 6, attack 5, hurt 2, death 8 | +| Environment | stone floor, fortress wall, fortress gate, battlefield fog | +| Combat effects | slash, hit, blood, ghost fire, death dissolve | +| Interface | HP, Boss, and sacrifice icons | +| Projectile | Ghost Arrow | + +### Final actor visual alignment + +Collision bodies and their origins are unchanged. Each character owns its +visual transform in its actor scene; equal numeric values for the two ghosts +are explicit per-scene declarations, not a shared global offset. + +| Actor | Frame | Declared pivot / foot | Sprite position | Sprite scale | Visual foot at actor origin | +| --- | --- | --- | --- | --- | --- | +| Player | 192×160 | (96, 150) | (0, -25.2) | 0.36 | 0.0 px | +| Ghost Melee | 192×160 | (96, 150) | (0, -25.2) | 0.36 | 0.0 px | +| Ghost Archer | 192×160 | (96, 150) | (0, -25.2) | 0.36 | 0.0 px | +| Gate Warden | 320×256 | (160, 248) | (0, -48) | 0.40 | 0.0 px | + +The validation formula is `sprite_y + (foot_y - frame_height / 2) * scale_y`. +`tests/cases/test_production_assets.gd` checks it against every instantiated +actor scene. + +## Validation + +- Godot 4.7.1 real-renderer captures: + `docs/screenshots/art_v3_wave.png`, `art_v3_boss.png`, + `art_v3_lineup.png`, and `art_v3_combat.png`. +- Full headless suite: **64 tests, 438 assertions, 0 failures**. +- Confirmed no missing textures, broken actor animations, or altered actor + collision/attack shapes. +- Confirmed Player, Ghost Melee, Ghost Archer, Gate Warden, and Ghost Arrow all + resolve their live visuals from `assets_v3/production/`. + +## Known limitations and remaining placeholders + +- The player jump state reuses the first two production idle frames. This is a + deliberate temporary fallback because Sprint 01 was limited to idle, walk, + attack, hurt, and death. +- The approved generated boards contain three unique Ghost Melee idle poses, + three unique Gate Warden idle poses, and seven unique Gate Warden death + poses. A settled frame is repeated to preserve the existing framework's + established frame counts and timings. +- The existing deep/tree/chain parallax composition and the health/stamina bar + frames remain in use. They were outside this sprint's approved replacement + list; the new fog layer, production environment tiles, gate, and icons render + with them. +- Future enemies, unused tiles, inventory/minimap UI, weapon icons, heavy + attack, additional Boss attacks, and audio remain intentionally untouched. + +## Recommended Sprint 02 + +Produce the missing player jump/fall set, replace the remaining parallax and +bar-frame presentation with V3-approved assets, then author additional content +only after separate art-direction approval. Do not combine that work with +Boss phase-two or new gameplay-state implementation. diff --git a/docs/screenshots/art_v3_boss.png b/docs/screenshots/art_v3_boss.png new file mode 100644 index 0000000..077a2d4 Binary files /dev/null and b/docs/screenshots/art_v3_boss.png differ diff --git a/docs/screenshots/art_v3_boss.png.import b/docs/screenshots/art_v3_boss.png.import new file mode 100644 index 0000000..28c7d5e --- /dev/null +++ b/docs/screenshots/art_v3_boss.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwcaoabx23jjq" +path="res://.godot/imported/art_v3_boss.png-45caaccd7baef6aa60844fa76b5bab76.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/screenshots/art_v3_boss.png" +dest_files=["res://.godot/imported/art_v3_boss.png-45caaccd7baef6aa60844fa76b5bab76.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=0 diff --git a/docs/screenshots/art_v3_combat.png b/docs/screenshots/art_v3_combat.png new file mode 100644 index 0000000..a7dd20b Binary files /dev/null and b/docs/screenshots/art_v3_combat.png differ diff --git a/docs/screenshots/art_v3_combat.png.import b/docs/screenshots/art_v3_combat.png.import new file mode 100644 index 0000000..2b559ca --- /dev/null +++ b/docs/screenshots/art_v3_combat.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fwgu07l748bg" +path="res://.godot/imported/art_v3_combat.png-30ea8e1ba16d194163f9ba6735a0f9fd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/screenshots/art_v3_combat.png" +dest_files=["res://.godot/imported/art_v3_combat.png-30ea8e1ba16d194163f9ba6735a0f9fd.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=0 diff --git a/docs/screenshots/art_v3_lineup.png b/docs/screenshots/art_v3_lineup.png new file mode 100644 index 0000000..27ba0f0 Binary files /dev/null and b/docs/screenshots/art_v3_lineup.png differ diff --git a/docs/screenshots/art_v3_lineup.png.import b/docs/screenshots/art_v3_lineup.png.import new file mode 100644 index 0000000..e0c14fe --- /dev/null +++ b/docs/screenshots/art_v3_lineup.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0gqod3fhwobq" +path="res://.godot/imported/art_v3_lineup.png-e2cff02048ff44575ddc39531ed795c8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/screenshots/art_v3_lineup.png" +dest_files=["res://.godot/imported/art_v3_lineup.png-e2cff02048ff44575ddc39531ed795c8.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=0 diff --git a/docs/screenshots/art_v3_wave.png b/docs/screenshots/art_v3_wave.png new file mode 100644 index 0000000..be34d4c Binary files /dev/null and b/docs/screenshots/art_v3_wave.png differ diff --git a/docs/screenshots/art_v3_wave.png.import b/docs/screenshots/art_v3_wave.png.import new file mode 100644 index 0000000..aede89e --- /dev/null +++ b/docs/screenshots/art_v3_wave.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1kdmm0nvceyr" +path="res://.godot/imported/art_v3_wave.png-0da9fd17f67c04a9cd266951d95cecc9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/screenshots/art_v3_wave.png" +dest_files=["res://.godot/imported/art_v3_wave.png-0da9fd17f67c04a9cd266951d95cecc9.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=0 diff --git a/scenes/arena.tscn b/scenes/arena.tscn index b2a2975..16e9b47 100644 --- a/scenes/arena.tscn +++ b/scenes/arena.tscn @@ -1,14 +1,15 @@ -[gd_scene load_steps=14 format=3 uid="uid://bnnarena00001"] +[gd_scene load_steps=15 format=3 uid="uid://bnnarena00001"] [ext_resource type="Script" path="res://scenes/arena.gd" id="1_arena"] [ext_resource type="Texture2D" path="res://assets/background/bg_deep.png" id="2_bg_deep"] [ext_resource type="Texture2D" path="res://assets/background/bg_tree.png" id="3_bg_tree"] [ext_resource type="Texture2D" path="res://assets/background/bg_broken_flag.png" id="4_bg_flag"] [ext_resource type="Texture2D" path="res://assets/background/bg_chains.png" id="5_bg_chains"] -[ext_resource type="Texture2D" path="res://assets/tiles/tile_floor.png" id="6_floor"] -[ext_resource type="Texture2D" path="res://assets/tiles/tile_stone_brick.png" id="7_brick"] -[ext_resource type="Texture2D" path="res://assets/tiles/tile_brazier.png" id="8_brazier"] -[ext_resource type="Texture2D" path="res://assets/tiles/tile_tombstone.png" id="9_tomb"] +[ext_resource type="Texture2D" path="res://assets_v3/production/environment/stone_floor.png" id="6_floor"] +[ext_resource type="Texture2D" path="res://assets_v3/production/environment/stone_wall.png" id="7_brick"] +[ext_resource type="SpriteFrames" path="res://visuals/ghost_fire_frames.tres" id="8_fire"] +[ext_resource type="Texture2D" path="res://assets_v3/production/environment/fortress_gate.png" id="9_gate"] +[ext_resource type="Texture2D" path="res://assets_v3/production/environment/battlefield_fog.png" id="10_fog"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_floor"] size = Vector2(1088, 56) @@ -79,6 +80,14 @@ position = Vector2(620, 0) centered = false texture = ExtResource("5_bg_chains") +[node name="Fog" type="Sprite2D" parent="Parallax/ChainLayer"] +texture_repeat = 2 +position = Vector2(0, 208) +centered = false +texture = ExtResource("10_fog") +region_enabled = true +region_rect = Rect2(0, 0, 1024, 96) + [node name="Terrain" type="Node2D" parent="."] [node name="Floor" type="StaticBody2D" parent="Terrain"] @@ -139,20 +148,24 @@ shape = SubResource("RectangleShape2D_ceiling") [node name="Props" type="Node2D" parent="."] -[node name="BrazierLeft" type="Sprite2D" parent="Props"] -position = Vector2(224, 272) -centered = false -texture = ExtResource("8_brazier") - -[node name="BrazierRight" type="Sprite2D" parent="Props"] -position = Vector2(768, 272) -centered = false -texture = ExtResource("8_brazier") - -[node name="Tombstone" type="Sprite2D" parent="Props"] -position = Vector2(512, 272) -centered = false -texture = ExtResource("9_tomb") +[node name="GhostFireLeft" type="AnimatedSprite2D" parent="Props"] +position = Vector2(224, 289) +scale = Vector2(0.5, 0.5) +sprite_frames = ExtResource("8_fire") +animation = &"burn" +autoplay = "burn" + +[node name="GhostFireRight" type="AnimatedSprite2D" parent="Props"] +position = Vector2(768, 289) +scale = Vector2(0.5, 0.5) +sprite_frames = ExtResource("8_fire") +animation = &"burn" +autoplay = "burn" + +[node name="FortressGate" type="Sprite2D" parent="Props"] +position = Vector2(512, 237) +scale = Vector2(0.35, 0.35) +texture = ExtResource("9_gate") [node name="Spawns" type="Node2D" parent="."] diff --git a/scenes/main.tscn b/scenes/main.tscn index 2ed3ee2..ef5b0fa 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://bnnmain0000001"] +[gd_scene load_steps=14 format=3 uid="uid://bnnmain0000001"] [ext_resource type="Script" path="res://scenes/main.gd" id="1_main"] [ext_resource type="PackedScene" path="res://scenes/arena.tscn" id="2_arena"] @@ -13,8 +13,7 @@ [ext_resource type="PackedScene" path="res://ui/result_screen.tscn" id="11_result"] [ext_resource type="PackedScene" path="res://ui/debug_panel.tscn" id="12_debug"] [ext_resource type="Script" path="res://ui/debug_shape_overlay.gd" id="13_shapes"] -[ext_resource type="Script" path="res://visuals/combat_effects.gd" id="14_effects"] -[ext_resource type="Texture2D" path="res://assets_v2/effects/hit.png" id="15_hit"] +[ext_resource type="Script" path="res://visuals/combat_feedback.gd" id="14_feedback"] [node name="Main" type="Node2D"] script = ExtResource("1_main") @@ -23,12 +22,6 @@ script = ExtResource("1_main") [node name="Actors" type="Node2D" parent="."] -[node name="CombatEffects" type="Node2D" parent="."] -script = ExtResource("14_effects") -hit_texture = ExtResource("15_hit") -hit_frames = 4 -hit_fps = 16.0 - [node name="RunCoordinator" type="Node" parent="."] script = ExtResource("3_coordinator") player_scene = ExtResource("4_player") @@ -53,3 +46,6 @@ actor_root_path = NodePath("../Actors") [node name="DebugShapes" type="Node2D" parent="DebugRoot"] script = ExtResource("13_shapes") + +[node name="CombatFeedback" type="Node" parent="."] +script = ExtResource("14_feedback") diff --git a/tests/cases/test_art_v2.gd b/tests/cases/test_art_v2.gd index 1114604..b5534bd 100644 --- a/tests/cases/test_art_v2.gd +++ b/tests/cases/test_art_v2.gd @@ -1,5 +1,5 @@ extends TestCase -## M1.5 Art V2 resource, state mapping and authored-frame timing coverage. +## Develop animation contracts mapped onto the approved Art V3 production art. const MAIN_SCENE := "res://scenes/main.tscn" const PLAYER_SCENE := "res://actors/player/player.tscn" @@ -43,7 +43,7 @@ func _spawn_enemy(scene_path: String, config_path: String, target: Node2D) -> En return enemy -func test_all_integrated_v2_resources_load_with_declared_animations() -> void: +func test_all_integrated_resources_load_with_declared_animations() -> void: var player_frames := load("res://assets_v2/godot/player_frames.tres") as SpriteFrames var melee_frames := load("res://assets_v2/godot/melee_ghost_frames.tres") as SpriteFrames var archer_frames := load("res://assets_v2/godot/ghost_archer_frames.tres") as SpriteFrames @@ -56,12 +56,12 @@ func test_all_integrated_v2_resources_load_with_declared_animations() -> void: assert_equal(melee_frames.get_frame_count(&"melee_ghost_attack"), 8, "melee attack has 8 frames") assert_equal(archer_frames.get_frame_count(&"ghost_archer_shoot"), 4, "archer shoot has 4 frames") assert_equal(boss_frames.get_frame_count(&"gate_warden_attack_1"), 10, "Boss attack has 10 frames") - assert_not_null(load("res://assets_v2/projectiles/ghost_fire_arrow.png"), "Ghost Arrow texture imports") - assert_not_null(load("res://assets_v2/effects/hit.png"), "hit effect imports") - assert_not_null(load("res://assets_v2/effects/blade_slash.png"), "slash effect imports") + assert_not_null(load("res://assets_v3/production/projectiles/ghost_arrow.png"), "V3 Ghost Arrow texture imports") + assert_not_null(load("res://assets_v3/production/effects/hit.png"), "V3 hit effect imports") + assert_not_null(load("res://assets_v3/production/effects/slash.png"), "V3 slash effect imports") -func test_actor_scenes_use_v2_frames_and_stable_foot_offsets() -> void: +func test_actor_scenes_use_v3_frames_and_stable_foot_positions() -> void: var player := (load(PLAYER_SCENE) as PackedScene).instantiate() as Player var melee := (load(MELEE_SCENE) as PackedScene).instantiate() as MeleeGhost var archer := (load(ARCHER_SCENE) as PackedScene).instantiate() as GhostArcher @@ -69,14 +69,14 @@ func test_actor_scenes_use_v2_frames_and_stable_foot_offsets() -> void: for actor in [player, melee, archer, boss]: tree.root.add_child(actor) _spawned.append(actor) - assert_equal(player.sprite.offset, Vector2(-48, -88), "player feet use V2 baseline") - assert_equal(melee.sprite.offset, Vector2(-48, -90), "melee feet use V2 baseline") - assert_equal(archer.sprite.offset, Vector2(-48, -88), "archer feet use V2 baseline") - assert_equal(boss.sprite.offset, Vector2(-96, -176), "Boss feet use V2 baseline") + assert_almost(player.sprite.position.y + (150.0 - 80.0) * player.sprite.scale.y, 0.0, "player V3 feet meet actor origin", 0.01) + assert_almost(melee.sprite.position.y + (150.0 - 80.0) * melee.sprite.scale.y, 0.0, "melee V3 feet meet actor origin", 0.01) + assert_almost(archer.sprite.position.y + (150.0 - 80.0) * archer.sprite.scale.y, 0.0, "archer V3 feet meet actor origin", 0.01) + assert_almost(boss.sprite.position.y + (248.0 - 128.0) * boss.sprite.scale.y, 0.0, "Boss V3 feet meet actor origin", 0.01) var arrow := (load(ARROW_SCENE) as PackedScene).instantiate() as GhostArrow tree.root.add_child(arrow) _spawned.append(arrow) - assert_true(arrow.uses_v2_texture(), "normal projectile rendering uses the supplied V2 texture") + assert_true(arrow.uses_v2_texture(), "normal projectile rendering uses the supplied V3 texture") assert_false(arrow.get_node("FallbackVisual").visible, "procedural fallback is hidden") diff --git a/tests/cases/test_production_assets.gd b/tests/cases/test_production_assets.gd new file mode 100644 index 0000000..75d303d --- /dev/null +++ b/tests/cases/test_production_assets.gd @@ -0,0 +1,128 @@ +extends TestCase +## Art V3 production validation: declared metadata, frame resources, scene-local +## foot alignment, transparency, and removal of live actor placeholders. + +const ACTORS := { + "player": { + "scene": "res://actors/player/player.tscn", + "frames": "res://assets_v2/godot/player_frames.tres", + "map": "res://assets_v3/production/player/frame_map.json", + "counts": {&"player_idle": 4, &"player_run": 6, &"player_jump": 2, &"player_fall": 2, &"player_light_attack_1": 8, &"player_hurt": 2, &"player_death": 6}, + }, + "ghost_melee": { + "scene": "res://actors/enemies/ghost_melee.tscn", + "frames": "res://assets_v2/godot/melee_ghost_frames.tres", + "map": "res://assets_v3/production/ghost_melee/frame_map.json", + "counts": {&"melee_ghost_idle": 4, &"melee_ghost_walk": 6, &"melee_ghost_attack": 8, &"melee_ghost_hurt": 2, &"melee_ghost_death": 4}, + }, + "ghost_archer": { + "scene": "res://actors/enemies/ghost_archer.tscn", + "frames": "res://assets_v2/godot/ghost_archer_frames.tres", + "map": "res://assets_v3/production/ghost_archer/frame_map.json", + "counts": {&"ghost_archer_idle": 4, &"ghost_archer_retreat": 6, &"ghost_archer_aim": 6, &"ghost_archer_shoot": 4, &"ghost_archer_hurt": 2, &"ghost_archer_death": 4}, + }, + "gate_warden": { + "scene": "res://actors/boss/boss.tscn", + "frames": "res://assets_v2/godot/gate_warden_frames.tres", + "map": "res://assets_v3/production/gate_warden/frame_map.json", + "counts": {&"gate_warden_idle": 4, &"gate_warden_walk": 6, &"gate_warden_attack_1": 10, &"gate_warden_hurt": 2, &"gate_warden_death": 8}, + }, +} + + +func test_actor_frame_maps_match_sprite_resources() -> void: + for actor_name: String in ACTORS: + var spec: Dictionary = ACTORS[actor_name] + var metadata := _read_json(spec["map"]) + assert_not_null(metadata, "%s frame map parses" % actor_name) + var frame_size := Vector2i(metadata["frame_size"][0], metadata["frame_size"][1]) + var frames := load(spec["frames"]) as SpriteFrames + assert_not_null(frames, "%s SpriteFrames loads" % actor_name) + for animation: StringName in spec["counts"]: + assert_true(frames.has_animation(animation), "%s has %s" % [actor_name, animation]) + assert_equal(frames.get_frame_count(animation), spec["counts"][animation], "%s %s frame count" % [actor_name, animation]) + var texture := frames.get_frame_texture(animation, 0) + assert_equal(texture.get_size(), Vector2(frame_size), "%s %s uses declared frame size" % [actor_name, animation]) + assert_true(texture is AtlasTexture, "%s %s uses an atlas frame" % [actor_name, animation]) + assert_true((texture as AtlasTexture).atlas.resource_path.begins_with("res://assets_v3/production/"), "%s %s resolves to V3 art" % [actor_name, animation]) + + +func test_declared_foot_positions_land_on_actor_origins() -> void: + for actor_name: String in ACTORS: + var spec: Dictionary = ACTORS[actor_name] + var metadata := _read_json(spec["map"]) + var scene := load(spec["scene"]) as PackedScene + var actor := scene.instantiate() as Node2D + var sprite := actor.get_node("Sprite") as AnimatedSprite2D + var frame_height := float(metadata["frame_size"][1]) + var foot_y := float(metadata["foot_position"][1]) + var visual_foot_y := sprite.position.y + (foot_y - frame_height * 0.5) * sprite.scale.y + assert_almost(visual_foot_y, 0.0, "%s visible foot meets stable actor origin" % actor_name, 0.01) + actor.free() + + +func test_every_production_frame_is_anchored_to_declared_baseline() -> void: + for actor_name: String in ACTORS: + var spec: Dictionary = ACTORS[actor_name] + var metadata := _read_json(spec["map"]) + var frame_width := int(metadata["frame_size"][0]) + var frame_height := int(metadata["frame_size"][1]) + var foot_y := int(metadata["foot_position"][1]) + for animation: String in metadata["animations"]: + var path := "res://assets_v3/production/%s/%s_%s.png" % [actor_name, actor_name, animation] + var image := Image.new() + assert_equal(image.load(ProjectSettings.globalize_path(path)), OK, "%s loads" % path) + var count := int(metadata["animations"][animation]["frames"]) + for frame_index in count: + var frame := image.get_region(Rect2i(frame_index * frame_width, 0, frame_width, frame_height)) + var used := frame.get_used_rect() + assert_equal(used.end.y, foot_y, "%s %s frame %d reaches declared foot baseline" % [actor_name, animation, frame_index]) + + +func test_production_pngs_are_rgba_and_have_transparent_margins() -> void: + var paths := [ + "res://assets_v3/production/player/player_idle.png", + "res://assets_v3/production/ghost_melee/ghost_melee_idle.png", + "res://assets_v3/production/ghost_archer/ghost_archer_idle.png", + "res://assets_v3/production/gate_warden/gate_warden_idle.png", + "res://assets_v3/production/effects/slash.png", + "res://assets_v3/production/icons/icon_hp.png", + "res://assets_v3/production/projectiles/ghost_arrow.png", + ] + for path: String in paths: + var image := Image.new() + assert_equal(image.load(ProjectSettings.globalize_path(path)), OK, "%s loads" % path) + assert_true(image.detect_alpha() != Image.ALPHA_NONE, "%s carries alpha" % path) + assert_equal(image.get_pixel(0, 0).a, 0.0, "%s has a transparent margin" % path) + + +func test_live_scenes_reference_v3_production_art() -> void: + var arrow := (load("res://actors/enemies/ghost_arrow.tscn") as PackedScene).instantiate() + assert_not_null(arrow.get_node_or_null("FallbackVisual"), "develop emergency fallback remains available") + assert_false((arrow.get_node("FallbackVisual") as CanvasItem).visible, "polygon arrow fallback is hidden") + var arrow_visual := arrow.get_node("Visual") as Sprite2D + assert_true(arrow_visual.texture.resource_path.begins_with("res://assets_v3/production/"), "arrow uses V3 texture") + arrow.free() + + var arena := (load("res://scenes/arena.tscn") as PackedScene).instantiate() + for node_path: String in ["Terrain/Floor/Surface", "Terrain/LeftWall/Surface", "Props/FortressGate"]: + var visual := arena.get_node(node_path) as Sprite2D + assert_true(visual.texture.resource_path.begins_with("res://assets_v3/production/"), "%s uses V3 texture" % node_path) + assert_not_null(arena.get_node_or_null("Props/GhostFireLeft"), "V3 ghost fire is present") + arena.free() + + var main := (load("res://scenes/main.tscn") as PackedScene).instantiate() + assert_not_null(main.get_node_or_null("CombatFeedback"), "one V3 combat-feedback observer is present") + assert_null(main.get_node_or_null("CombatEffects"), "legacy hit observer is not duplicated") + var hud := main.get_node("UIRoot/Hud") + assert_true((hud.get_node("Player/Icon") as TextureRect).texture.resource_path.begins_with("res://assets_v3/production/"), "player HUD uses V3 HP icon") + assert_true((hud.get_node("Boss/Icon") as TextureRect).texture.resource_path.begins_with("res://assets_v3/production/"), "Boss HUD uses V3 icon") + main.free() + + +func _read_json(path: String) -> Dictionary: + var file := FileAccess.open(path, FileAccess.READ) + if file == null: + return {} + var parsed: Variant = JSON.parse_string(file.get_as_text()) + return parsed if parsed is Dictionary else {} diff --git a/tools/capture_gameplay.gd b/tools/capture_gameplay.gd new file mode 100644 index 0000000..a550c7e --- /dev/null +++ b/tools/capture_gameplay.gd @@ -0,0 +1,80 @@ +extends Node +## Reproducible Art V3 runtime capture harness. +## +## Usage: +## godot --path . res://tools/capture_gameplay.tscn -- wave +## godot --path . res://tools/capture_gameplay.tscn -- boss +## godot --path . res://tools/capture_gameplay.tscn -- lineup +## godot --path . res://tools/capture_gameplay.tscn -- combat + +const MAIN := preload("res://scenes/main.tscn") + + +func _ready() -> void: + var main := MAIN.instantiate() as Main + add_child(main) + for _frame in 12: + await get_tree().process_frame + + var kind := "wave" + var args := OS.get_cmdline_user_args() + if not args.is_empty(): + kind = args[0] + var coordinator := main.coordinator() + var capture_delay := 30 + if kind == "combat": + var player := coordinator.player() + player.global_position = Vector2(360.0, 304.0) + var live := coordinator.live_enemies() + for index in live.size(): + if index == 0: + live[index].global_position = Vector2(380.0, 304.0) + live[index].acquire_target(null) + else: + live[index].queue_free() + for _frame in 2: + await get_tree().physics_frame + Input.action_press(&"light_attack") + for _frame in 2: + await get_tree().physics_frame + Input.action_release(&"light_attack") + for _frame in 8: + await get_tree().physics_frame + capture_delay = 1 + elif kind == "lineup": + var player := coordinator.player() + player.global_position = Vector2(300.0, 304.0) + player.camera.position.x = 180.0 + main.get_node("Arena/Props/FortressGate").visible = false + var live := coordinator.live_enemies() + for index in live.size(): + if index == 0: + live[index].global_position = Vector2(560.0, 304.0) + live[index].acquire_target(null) + else: + live[index].queue_free() + var melee := (load("res://actors/enemies/ghost_melee.tscn") as PackedScene).instantiate() as EnemyBase + main.get_node("Actors").add_child(melee) + melee.global_position = Vector2(430.0, 304.0) + melee.initialize(load("res://data/actors/ghost_melee.tres") as EnemyConfig, player) + melee.acquire_target(null) + coordinator.begin_boss() + coordinator.boss().global_position = Vector2(700.0, 304.0) + coordinator.boss().acquire_target(null) + elif kind == "boss": + coordinator.player().global_position = Vector2(650.0, 304.0) + coordinator.begin_boss() + else: + coordinator.player().global_position = Vector2(360.0, 304.0) + + for _frame in capture_delay: + await get_tree().process_frame + var image := get_viewport().get_texture().get_image() + var output := "res://docs/screenshots/art_v3_%s.png" % kind + var error := image.save_png(output) + if error != OK: + push_error("Could not write %s: %s" % [output, error_string(error)]) + get_tree().quit(1) + return + print("Wrote %s" % output) + get_tree().quit() diff --git a/tools/capture_gameplay.tscn b/tools/capture_gameplay.tscn new file mode 100644 index 0000000..2e05596 --- /dev/null +++ b/tools/capture_gameplay.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://tools/capture_gameplay.gd" id="1_capture"] + +[node name="CaptureGameplay" type="Node"] +script = ExtResource("1_capture") diff --git a/tools/generate_sprite_frames.py b/tools/generate_sprite_frames.py index dc3fb82..3de2f84 100644 --- a/tools/generate_sprite_frames.py +++ b/tools/generate_sprite_frames.py @@ -23,55 +23,68 @@ REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent -# actor -> (output path, frame width, frame height, [(anim, sheet, frames, fps, loop)]) +# actor -> (output path, frame width, frame height, +# [(animation, sheet, source-frame indices, fps, loop)]) +# +# Animation names remain the gameplay framework's established names. Art V3 +# calls locomotion "walk" in metadata, while the state machines call it "run". ACTORS = { "player": ( - "actors/player/player_frames.tres", - 48, - 48, + "assets_v2/godot/player_frames.tres", + 192, + 160, [ - ("idle", "assets/player/player_idle.png", 4, 8.0, True), - ("run", "assets/player/player_run.png", 6, 12.0, True), - ("jump", "assets/player/player_jump.png", 2, 10.0, False), - ("attack", "assets/player/player_attack.png", 4, 14.0, False), - ("hurt", "assets/player/player_hurt.png", 2, 10.0, False), - ("death", "assets/player/player_death.png", 6, 8.0, False), + ("player_idle", "assets_v3/production/player/player_idle.png", [0, 1, 2, 3], 6.0, True), + ("player_run", "assets_v3/production/player/player_walk.png", [0, 1, 2, 3, 4, 5], 10.0, True), + # Sprint 01 has no V3 jump/fall set. Reuse distinct idle pairs so + # develop's rising/falling animation contract remains available. + ("player_jump", "assets_v3/production/player/player_idle.png", [0, 1], 10.0, False), + ("player_fall", "assets_v3/production/player/player_idle.png", [2, 3], 10.0, False), + # Develop gates the hitbox on frames 4-5. Repeat each approved V3 + # pose twice to retain the eight-frame startup/active/recovery map. + ("player_light_attack_1", "assets_v3/production/player/player_attack.png", [0, 0, 1, 1, 2, 2, 3, 3], 12.0, False), + ("player_light_attack_2", "assets_v3/production/player/player_attack.png", [0, 0, 1, 1, 2, 2, 3, 3], 12.0, False), + ("player_heavy_attack", "assets_v3/production/player/player_attack.png", [0, 0, 1, 1, 2, 2, 3, 3], 10.0, False), + ("player_hurt", "assets_v3/production/player/player_hurt.png", [0, 1], 8.0, False), + ("player_death", "assets_v3/production/player/player_death.png", [0, 1, 2, 3, 4, 5], 8.0, False), ], ), "ghost_melee": ( - "actors/enemies/ghost_melee_frames.tres", - 48, - 48, + "assets_v2/godot/melee_ghost_frames.tres", + 192, + 160, [ - ("idle", "assets/enemy/ghost_melee_idle.png", 4, 8.0, True), - ("run", "assets/enemy/ghost_melee_run.png", 6, 10.0, True), - ("attack", "assets/enemy/ghost_melee_attack.png", 4, 12.0, False), - ("hurt", "assets/enemy/ghost_melee_hurt.png", 2, 10.0, False), - ("death", "assets/enemy/ghost_melee_death.png", 4, 8.0, False), + ("melee_ghost_idle", "assets_v3/production/ghost_melee/ghost_melee_idle.png", [0, 1, 2, 3], 6.0, True), + ("melee_ghost_walk", "assets_v3/production/ghost_melee/ghost_melee_walk.png", [0, 1, 2, 3, 4, 5], 9.0, True), + ("melee_ghost_attack", "assets_v3/production/ghost_melee/ghost_melee_attack.png", [0, 0, 1, 1, 2, 2, 3, 3], 10.0, False), + ("melee_ghost_hurt", "assets_v3/production/ghost_melee/ghost_melee_hurt.png", [0, 1], 8.0, False), + ("melee_ghost_death", "assets_v3/production/ghost_melee/ghost_melee_death.png", [0, 1, 2, 3], 7.0, False), ], ), "ghost_archer": ( - "actors/enemies/ghost_archer_frames.tres", - 48, - 48, + "assets_v2/godot/ghost_archer_frames.tres", + 192, + 160, [ - ("idle", "assets/enemy/ghost_archer_idle.png", 4, 8.0, True), - ("run", "assets/enemy/ghost_archer_run.png", 6, 10.0, True), - ("attack", "assets/enemy/ghost_archer_attack.png", 4, 12.0, False), - ("hurt", "assets/enemy/ghost_archer_hurt.png", 2, 10.0, False), - ("death", "assets/enemy/ghost_archer_death.png", 4, 8.0, False), + ("ghost_archer_idle", "assets_v3/production/ghost_archer/ghost_archer_idle.png", [0, 1, 2, 3], 6.0, True), + ("ghost_archer_retreat", "assets_v3/production/ghost_archer/ghost_archer_walk.png", [0, 1, 2, 3, 4, 5], 9.0, True), + ("ghost_archer_aim", "assets_v3/production/ghost_archer/ghost_archer_attack.png", [0, 0, 1, 1, 1, 1], 8.0, False), + ("ghost_archer_shoot", "assets_v3/production/ghost_archer/ghost_archer_attack.png", [1, 2, 2, 3], 14.0, False), + ("ghost_archer_hurt", "assets_v3/production/ghost_archer/ghost_archer_hurt.png", [0, 1], 8.0, False), + ("ghost_archer_death", "assets_v3/production/ghost_archer/ghost_archer_death.png", [0, 1, 2, 3], 7.0, False), ], ), "boss": ( - "actors/boss/boss_frames.tres", - 96, - 96, + "assets_v2/godot/gate_warden_frames.tres", + 320, + 256, [ - ("idle", "assets/boss/boss_idle.png", 4, 6.0, True), - ("run", "assets/boss/boss_run.png", 6, 8.0, True), - ("attack", "assets/boss/boss_attack.png", 5, 10.0, False), - ("hurt", "assets/boss/boss_hurt.png", 2, 8.0, False), - ("death", "assets/boss/boss_death.png", 8, 6.0, False), + ("gate_warden_idle", "assets_v3/production/gate_warden/gate_warden_idle.png", [0, 1, 2, 3], 5.0, True), + ("gate_warden_walk", "assets_v3/production/gate_warden/gate_warden_walk.png", [0, 1, 2, 3, 4, 5], 7.0, True), + ("gate_warden_attack_1", "assets_v3/production/gate_warden/gate_warden_attack.png", [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], 9.0, False), + ("gate_warden_attack_2", "assets_v3/production/gate_warden/gate_warden_attack.png", [0, 0, 1, 1, 2, 2, 3, 3, 4, 4], 8.0, False), + ("gate_warden_hurt", "assets_v3/production/gate_warden/gate_warden_hurt.png", [0, 1], 7.0, False), + ("gate_warden_death", "assets_v3/production/gate_warden/gate_warden_death.png", [0, 1, 2, 3, 4, 5, 6, 7], 6.0, False), ], ), } @@ -82,18 +95,19 @@ ) -def verify_sheet(sheet: pathlib.Path, frames: int, width: int, height: int) -> None: +def verify_sheet(sheet: pathlib.Path, frame_indices: list[int], width: int, height: int) -> None: """Fail loudly if a sheet does not match the frame table.""" try: from PIL import Image # optional; skip verification when unavailable except ImportError: return with Image.open(sheet) as image: - expected = (frames * width, height) - if image.size != expected: + source_frames = max(frame_indices) + 1 + expected = (source_frames * width, height) + if image.height != height or image.width < expected[0] or image.width % width != 0: raise SystemExit( f"{sheet.relative_to(REPO_ROOT)} is {image.size}, " - f"expected {expected} for {frames} frames of {width}x{height}" + f"expected at least {expected} for indices {frame_indices} at {width}x{height}" ) @@ -103,19 +117,19 @@ def build(actor: str) -> str: sub_lines: list[str] = [] animation_entries: list[str] = [] - for index, (anim, sheet, frames, fps, loop) in enumerate(animations): - verify_sheet(REPO_ROOT / sheet, frames, frame_w, frame_h) + for index, (anim, sheet, frame_indices, fps, loop) in enumerate(animations): + verify_sheet(REPO_ROOT / sheet, frame_indices, frame_w, frame_h) ext_id = f"{index + 1}_{anim}" ext_lines.append( f'[ext_resource type="Texture2D" path="res://{sheet}" id="{ext_id}"]' ) frame_refs = [] - for frame in range(frames): + for frame, source_frame in enumerate(frame_indices): sub_id = f"AtlasTexture_{anim}_{frame}" sub_lines.append( f'[sub_resource type="AtlasTexture" id="{sub_id}"]\n' f'atlas = ExtResource("{ext_id}")\n' - f"region = Rect2({frame * frame_w}, 0, {frame_w}, {frame_h})" + f"region = Rect2({source_frame * frame_w}, 0, {frame_w}, {frame_h})" ) frame_refs.append( '{\n"duration": 1.0,\n' diff --git a/ui/hud.tscn b/ui/hud.tscn index 37906a5..7e809c1 100644 --- a/ui/hud.tscn +++ b/ui/hud.tscn @@ -1,13 +1,14 @@ -[gd_scene load_steps=9 format=3 uid="uid://bnnhud0000001"] +[gd_scene load_steps=10 format=3 uid="uid://bnnhud0000001"] [ext_resource type="Script" path="res://ui/hud.gd" id="1_hud"] [ext_resource type="Texture2D" path="res://assets/ui/ui_health_bar.png" id="2_health_bar"] [ext_resource type="Texture2D" path="res://assets/ui/ui_stamina_bar.png" id="3_stamina_bar"] -[ext_resource type="Texture2D" path="res://assets_v2/icons/icon_yang.png" id="4_icon_hp"] -[ext_resource type="Texture2D" path="res://assets_v2/icons/icon_obsession.png" id="5_icon_boss"] +[ext_resource type="Texture2D" path="res://assets_v3/production/icons/icon_hp.png" id="4_icon_hp"] +[ext_resource type="Texture2D" path="res://assets_v3/production/icons/icon_boss.png" id="5_icon_boss"] [ext_resource type="Texture2D" path="res://assets_v2/icons/icon_qi.png" id="6_icon_qi"] [ext_resource type="Texture2D" path="res://assets_v2/icons/icon_songdao.png" id="7_icon_attack"] [ext_resource type="Texture2D" path="res://assets_v2/icons/icon_ghostfire.png" id="8_icon_imbalance"] +[ext_resource type="Texture2D" path="res://assets_v2/icons/icon_obsession.png" id="9_icon_integrity"] [node name="Hud" type="CanvasLayer"] script = ExtResource("1_hud") @@ -23,6 +24,7 @@ offset_right = 22.0 offset_bottom = 22.0 texture = ExtResource("4_icon_hp") expand_mode = 1 +stretch_mode = 5 [node name="StaminaIcon" type="TextureRect" parent="Player"] offset_left = 6.0 @@ -84,7 +86,7 @@ offset_left = 6.0 offset_top = 61.0 offset_right = 20.0 offset_bottom = 75.0 -texture = ExtResource("5_icon_boss") +texture = ExtResource("9_icon_integrity") expand_mode = 1 [node name="ImbalanceIcon" type="TextureRect" parent="Player"] @@ -107,6 +109,7 @@ offset_right = 36.0 offset_bottom = 36.0 texture = ExtResource("5_icon_boss") expand_mode = 1 +stretch_mode = 5 [node name="BossBar" type="TextureRect" parent="Boss"] offset_left = 40.0 diff --git a/ui/sacrifice_panel.tscn b/ui/sacrifice_panel.tscn index 1a45ce0..d01867c 100644 --- a/ui/sacrifice_panel.tscn +++ b/ui/sacrifice_panel.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://bnnsacpanel001"] [ext_resource type="Script" path="res://ui/sacrifice_panel.gd" id="1_panel"] -[ext_resource type="Texture2D" path="res://assets_v2/icons/icon_talisman.png" id="2_icon"] +[ext_resource type="Texture2D" path="res://assets_v3/production/icons/icon_sacrifice.png" id="2_icon"] [node name="SacrificePanel" type="CanvasLayer"] layer = 5 @@ -29,6 +29,7 @@ offset_right = 40.0 offset_bottom = 40.0 texture = ExtResource("2_icon") expand_mode = 1 +stretch_mode = 5 [node name="Title" type="Label" parent="Root/Panel"] offset_left = 46.0 diff --git a/visuals/combat_feedback.gd b/visuals/combat_feedback.gd new file mode 100644 index 0000000..3e2dff8 --- /dev/null +++ b/visuals/combat_feedback.gd @@ -0,0 +1,151 @@ +extends Node +## Presentation-only observer for confirmed combat events. +## +## This node never calculates or applies damage. It consumes the frozen +## EventBus payload after CombatResolver has completed, then creates transient +## visual/audio-timing feedback only. + +const EFFECTS := { + &"slash": { + "texture": preload("res://assets_v3/production/effects/slash.png"), + "frame_size": Vector2i(96, 64), "frames": 4, "fps": 12.0, + }, + &"hit": { + "texture": preload("res://assets_v3/production/effects/hit.png"), + "frame_size": Vector2i(64, 64), "frames": 4, "fps": 16.0, + }, + &"blood": { + "texture": preload("res://assets_v3/production/effects/blood.png"), + "frame_size": Vector2i(96, 64), "frames": 4, "fps": 14.0, + }, + &"death": { + "texture": preload("res://assets_v3/production/effects/death.png"), + "frame_size": Vector2i(64, 80), "frames": 6, "fps": 10.0, + }, +} + +var _hit_stop_active := false + + +func _ready() -> void: + EventBus.hit_dealt.connect(_on_hit) + EventBus.hit_taken.connect(_on_hit) + EventBus.enemy_died.connect(_on_death) + EventBus.boss_died.connect(_on_death) + EventBus.player_died.connect(_on_player_death) + + +func _exit_tree() -> void: + # A run restart or scene transition can destroy this observer while the + # unscaled timer is pending. Never let presentation timing leak globally. + if _hit_stop_active: + Engine.time_scale = 1.0 + _hit_stop_active = false + + +func _on_hit(payload: Dictionary) -> void: + if float(payload.get("final_damage", 0.0)) <= 0.0: + return + var target := _find_actor(StringName(payload.get("target_id", &"unknown"))) + if target == null: + return + var point := target.global_position + Vector2(0.0, -18.0) + _spawn_effect(&"hit", point, 0.52) + _spawn_effect(&"blood", point + Vector2(5.0, 2.0), 0.42) + _spawn_damage_number(point, float(payload["final_damage"]), bool(payload.get("is_critical", false))) + _flash_actor(target) + _shake_camera() + _start_hit_stop() + + +func _on_death(payload: Dictionary) -> void: + var actor := _find_actor(StringName(payload.get("actor_id", &"unknown"))) + if actor != null and actor.get_node_or_null(^"DeathEffect") == null: + _spawn_effect(&"death", actor.global_position + Vector2(0.0, -16.0), 0.62) + + +func _on_player_death(_payload: Dictionary) -> void: + var player := _find_actor(&"player") + if player != null and player.get_node_or_null(^"DeathEffect") == null: + _spawn_effect(&"death", player.global_position + Vector2(0.0, -16.0), 0.62) + + +func _spawn_effect(effect_name: StringName, world_position: Vector2, visual_scale: float) -> void: + var spec: Dictionary = EFFECTS[effect_name] + var frames := SpriteFrames.new() + frames.add_animation(&"effect") + frames.set_animation_loop(&"effect", false) + frames.set_animation_speed(&"effect", float(spec["fps"])) + for index in int(spec["frames"]): + var atlas := AtlasTexture.new() + atlas.atlas = spec["texture"] + var frame_size: Vector2i = spec["frame_size"] + atlas.region = Rect2(index * frame_size.x, 0, frame_size.x, frame_size.y) + frames.add_frame(&"effect", atlas) + var effect := AnimatedSprite2D.new() + effect.sprite_frames = frames + effect.animation = &"effect" + effect.global_position = world_position + effect.scale = Vector2.ONE * visual_scale + effect.z_index = 20 + add_child(effect) + effect.animation_finished.connect(effect.queue_free) + effect.play() + + +func _spawn_damage_number(world_position: Vector2, amount: float, critical: bool) -> void: + var label := Label.new() + label.text = str(roundi(amount)) + label.global_position = world_position + Vector2(-8.0, -6.0) + label.z_index = 24 + label.add_theme_font_size_override("font_size", 10 if not critical else 12) + label.add_theme_color_override("font_color", Color("f1d79b") if not critical else Color("fff0ae")) + label.add_theme_color_override("font_outline_color", Color("251c24")) + label.add_theme_constant_override("outline_size", 2) + add_child(label) + var tween := create_tween().set_parallel(true) + tween.tween_property(label, "position", label.position + Vector2(0.0, -18.0), 0.42) + tween.tween_property(label, "modulate:a", 0.0, 0.42).set_delay(0.12) + tween.chain().tween_callback(label.queue_free) + + +func _flash_actor(actor: Node) -> void: + var sprite := actor.get_node_or_null("Sprite") as CanvasItem + if sprite == null: + return + var original := sprite.modulate + sprite.modulate = Color(1.0, 0.58, 0.5, original.a) + create_tween().tween_property(sprite, "modulate", original, 0.09) + + +func _shake_camera() -> void: + var camera := get_viewport().get_camera_2d() + if camera == null: + return + var original := camera.offset + var tween := create_tween() + tween.tween_property(camera, "offset", original + Vector2(2.0, -1.0), 0.025) + tween.tween_property(camera, "offset", original + Vector2(-1.0, 1.0), 0.025) + tween.tween_property(camera, "offset", original, 0.035) + + +func _start_hit_stop() -> void: + if _hit_stop_active: + return + _hit_stop_active = true + Engine.time_scale = 0.12 + await get_tree().create_timer(0.035, true, false, true).timeout + Engine.time_scale = 1.0 + _hit_stop_active = false + + +func _find_actor(wanted_id: StringName) -> Node2D: + for node in get_tree().get_nodes_in_group(&"combat_actor"): + if node.has_method("actor_id") and node.call("actor_id") == wanted_id: + return node as Node2D + # Existing actors predate the presentation group, so retain a read-only + # fallback that discovers the same Damageable contract recursively. + for node in get_tree().root.find_children("*", "Node2D", true, false): + if node.has_method("actor_id") and node.call("actor_id") == wanted_id: + return node as Node2D + return null diff --git a/visuals/ghost_fire_frames.tres b/visuals/ghost_fire_frames.tres new file mode 100644 index 0000000..2ac11d8 --- /dev/null +++ b/visuals/ghost_fire_frames.tres @@ -0,0 +1,35 @@ +[gd_resource type="SpriteFrames" load_steps=8 format=3] + +[ext_resource type="Texture2D" path="res://assets_v3/production/effects/ghost_fire.png" id="1_fire"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_0"] +atlas = ExtResource("1_fire") +region = Rect2(0, 0, 64, 64) + +[sub_resource type="AtlasTexture" id="AtlasTexture_1"] +atlas = ExtResource("1_fire") +region = Rect2(64, 0, 64, 64) + +[sub_resource type="AtlasTexture" id="AtlasTexture_2"] +atlas = ExtResource("1_fire") +region = Rect2(128, 0, 64, 64) + +[sub_resource type="AtlasTexture" id="AtlasTexture_3"] +atlas = ExtResource("1_fire") +region = Rect2(192, 0, 64, 64) + +[sub_resource type="AtlasTexture" id="AtlasTexture_4"] +atlas = ExtResource("1_fire") +region = Rect2(256, 0, 64, 64) + +[sub_resource type="AtlasTexture" id="AtlasTexture_5"] +atlas = ExtResource("1_fire") +region = Rect2(320, 0, 64, 64) + +[resource] +animations = [{ +"frames": [{"duration": 1.0, "texture": SubResource("AtlasTexture_0")}, {"duration": 1.0, "texture": SubResource("AtlasTexture_1")}, {"duration": 1.0, "texture": SubResource("AtlasTexture_2")}, {"duration": 1.0, "texture": SubResource("AtlasTexture_3")}, {"duration": 1.0, "texture": SubResource("AtlasTexture_4")}, {"duration": 1.0, "texture": SubResource("AtlasTexture_5")}], +"loop": true, +"name": &"burn", +"speed": 10.0 +}]