upd: sync local changes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b243a318f4
commit
214ddb32fc
20 files changed
+120
-23
No files matched your search
@@ -1,37 +1,53 @@
|
|||||||
{
|
{
|
||||||
"id": "card_novel",
|
"id": "card_novel",
|
||||||
|
"kind": "game",
|
||||||
"name": "Card Novel",
|
"name": "Card Novel",
|
||||||
"author": "ct",
|
"author": "ct",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A visual novel with turn-based battles resolved as a card game: story core, battle engine, card layer and the novel interface.",
|
"description": "A visual novel with turn-based battles resolved as a card game: story core, battle engine, card layer and the novel interface.",
|
||||||
|
"locale": [
|
||||||
|
{
|
||||||
|
"lang": "ru",
|
||||||
|
"name": "Карточная новелла",
|
||||||
|
"description": "Визуальная новелла с пошаговыми боями в виде карточной игры: сюжет, боевой движок, карты и интерфейс новеллы."
|
||||||
|
}
|
||||||
|
],
|
||||||
"mechanics": [
|
"mechanics": [
|
||||||
{
|
{
|
||||||
"id": "vn_core",
|
"id": "vn_core",
|
||||||
"name": "Novel Core",
|
"name": "Novel Core",
|
||||||
|
"role": "story",
|
||||||
"description": "Scenes, scenarios, dialogue and the story engine.",
|
"description": "Scenes, scenarios, dialogue and the story engine.",
|
||||||
|
"locale": [
|
||||||
|
{ "lang": "ru", "name": "Ядро новеллы", "description": "Сцены, сценарии, диалоги и движок истории." }
|
||||||
|
],
|
||||||
"mods": ["visual_novel_core>=1"]
|
"mods": ["visual_novel_core>=1"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "story",
|
"id": "story",
|
||||||
"name": "Story",
|
"name": "Story",
|
||||||
|
"role": "content",
|
||||||
"description": "The bundled story content.",
|
"description": "The bundled story content.",
|
||||||
"mods": ["murakami>=1"]
|
"mods": ["murakami>=1"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "battle",
|
"id": "battle",
|
||||||
"name": "Turn Battle",
|
"name": "Turn Battle",
|
||||||
|
"role": "battle",
|
||||||
"description": "Turn-based combat foundation.",
|
"description": "Turn-based combat foundation.",
|
||||||
"mods": ["turn_battle_base>=1"]
|
"mods": ["turn_battle_base>=1"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cards",
|
"id": "cards",
|
||||||
"name": "Card Game",
|
"name": "Card Game",
|
||||||
|
"role": "cards",
|
||||||
"description": "Card hands, decks and card-driven battle actions.",
|
"description": "Card hands, decks and card-driven battle actions.",
|
||||||
"mods": ["card_battle>=1"]
|
"mods": ["card_battle>=1"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "interface",
|
"id": "interface",
|
||||||
"name": "Interface",
|
"name": "Interface",
|
||||||
|
"role": "ui",
|
||||||
"description": "Shared GUI panels and the narrative HUD.",
|
"description": "Shared GUI panels and the narrative HUD.",
|
||||||
"mods": ["interface>=1"]
|
"mods": ["interface>=1"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod_card_battle_name=CardBattle
|
mod_card_battle_name=CardBattle
|
||||||
mod_card_battle_desc=Card battle mechanics
|
mod_card_battle_desc=Card battle implementation on top of turn_battle_base: an action-card hand with attack/defence values, character cards, battle HUD, log and banners, end-turn flow and its own battle sounds.
|
||||||
|
|
||||||
battle/end_turn=End turn
|
battle/end_turn=End turn
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
mod_card_battle_name=Карточная битва
|
mod_card_battle_name=Карточная битва
|
||||||
mod_card_battle_desc=Механики карточных сражений
|
mod_card_battle_desc=Карточные сражения на платформе turn_battle_base: рука боевых карточек (атака/защита), карточки персонажей, боевой HUD, лог и баннеры, завершение хода и свои звуки боя.
|
||||||
|
|
||||||
battle/end_turn=Конец хода
|
battle/end_turn=Конец хода
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
"name": "CardBattle",
|
"name": "CardBattle",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "ct",
|
"author": "ct",
|
||||||
"description": "Card battle mechanics",
|
"description": "Card battle implementation on top of turn_battle_base: an action-card hand with attack/defence values, character cards, battle HUD, log and banners, end-turn flow and its own battle sounds.",
|
||||||
"category": "gameplay",
|
"category": "gameplay",
|
||||||
"sources": [
|
"sources": [
|
||||||
"src/**/*.cs"
|
"src/**/*.cs"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene format=3]
|
[gd_scene format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="src/UI/CharacterCardNode.cs" id="1_script"]
|
[ext_resource type="Script" path="src/UI/CharacterCardNode.cs" id="1_script"]
|
||||||
|
|
||||||
@@ -142,10 +142,28 @@ layout_mode = 2
|
|||||||
size_flags_vertical = 4
|
size_flags_vertical = 4
|
||||||
theme_override_font_sizes/font_size = 11
|
theme_override_font_sizes/font_size = 11
|
||||||
|
|
||||||
[node name="HpBar" type="ProgressBar" parent="Info/Column"]
|
[node name="HpBarStack" type="Control" parent="Info/Column"]
|
||||||
custom_minimum_size = Vector2(0, 7)
|
custom_minimum_size = Vector2(0, 7)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_vertical = 4
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="ShieldBar" type="ProgressBar" parent="Info/Column/HpBarStack"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
show_percentage = false
|
||||||
|
|
||||||
|
[node name="HpBar" type="ProgressBar" parent="Info/Column/HpBarStack"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
show_percentage = false
|
show_percentage = false
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,27 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class AbstractBattleAction : IBattleAction
|
public abstract class AbstractBattleAction : IBattleAction
|
||||||
{
|
{
|
||||||
|
/// <summary>Seconds timestamp of the current phase start (used for phase progress); -1 before the first phase.</summary>
|
||||||
protected double Timestamp { get; set; } = -1;
|
protected double Timestamp { get; set; } = -1;
|
||||||
|
/// <summary>Playback speed multiplier applied to all phase durations.</summary>
|
||||||
protected float Speed { get; set; }
|
protected float Speed { get; set; }
|
||||||
|
/// <summary>The action definition whose stats drive the animation.</summary>
|
||||||
protected ActionCharacter Action { get; set; }
|
protected ActionCharacter Action { get; set; }
|
||||||
|
/// <summary>Acting card node.</summary>
|
||||||
protected CharacterCardNode Source { get; set; }
|
protected CharacterCardNode Source { get; set; }
|
||||||
|
/// <summary>Receiving card node.</summary>
|
||||||
protected CharacterCardNode Target { get; set; }
|
protected CharacterCardNode Target { get; set; }
|
||||||
|
/// <summary>Visual control of the source card (null-safe abort when freed mid-animation).</summary>
|
||||||
protected Control SourceControl { get; set; }
|
protected Control SourceControl { get; set; }
|
||||||
|
/// <summary>Source position captured in <see cref="DoStart"/> for restoration in <see cref="DoEnd"/>.</summary>
|
||||||
protected Vector2 SourcePos { get; set; }
|
protected Vector2 SourcePos { get; set; }
|
||||||
|
/// <summary>Source rotation captured in <see cref="DoStart"/>.</summary>
|
||||||
protected float SourceRot { get; set; }
|
protected float SourceRot { get; set; }
|
||||||
|
/// <summary>Visual control of the target card.</summary>
|
||||||
protected Control TargetControl { get; set; }
|
protected Control TargetControl { get; set; }
|
||||||
|
/// <summary>Target position captured in <see cref="DoStart"/>.</summary>
|
||||||
protected Vector2 TargetPos { get; set; }
|
protected Vector2 TargetPos { get; set; }
|
||||||
|
/// <summary>Target rotation captured in <see cref="DoStart"/>.</summary>
|
||||||
protected float TargetRot { get; set; }
|
protected float TargetRot { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -41,8 +52,11 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
return DoInternalAction();
|
return DoInternalAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Frame tick of the animation; implementors advance phases and return true when finished.</summary>
|
||||||
protected abstract bool DoInternalAction();
|
protected abstract bool DoInternalAction();
|
||||||
|
/// <summary>Phase setup called once before the first <see cref="DoInternalAction"/> tick.</summary>
|
||||||
protected abstract void DoInternalStart();
|
protected abstract void DoInternalStart();
|
||||||
|
/// <summary>Cleanup called once after completion — restore captured positions/rotations here.</summary>
|
||||||
protected abstract void DoInternalEnd();
|
protected abstract void DoInternalEnd();
|
||||||
|
|
||||||
protected AbstractBattleAction(CharacterCardNode source, CharacterCardNode target, ActionCharacter action, float speed = 1)
|
protected AbstractBattleAction(CharacterCardNode source, CharacterCardNode target, ActionCharacter action, float speed = 1)
|
||||||
|
|||||||
@@ -69,9 +69,10 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
movementPattern = (MovementPattern)GD.RandRange(0, 5);
|
movementPattern = (MovementPattern)GD.RandRange(0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Resets the phase clock and starts the attack sequence from the Wait phase.</summary>
|
||||||
protected override void DoInternalStart()
|
protected override void DoInternalStart()
|
||||||
{
|
{
|
||||||
Timestamp = Time.GetTicksUsec() / 1_000_000.0;
|
Timestamp = Godot.Time.GetTicksUsec() / 1_000_000.0;
|
||||||
damageApplied = false;
|
damageApplied = false;
|
||||||
stunEffectSpawned = false;
|
stunEffectSpawned = false;
|
||||||
phase = ActionPhase.Wait;
|
phase = ActionPhase.Wait;
|
||||||
@@ -80,7 +81,7 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
|
|
||||||
private float GetPhaseProgress()
|
private float GetPhaseProgress()
|
||||||
{
|
{
|
||||||
float elapsed = (float)(Time.GetTicksUsec() / 1_000_000.0 - Timestamp) * Speed * (float)Engine.TimeScale;
|
float elapsed = (float)(Godot.Time.GetTicksUsec() / 1_000_000.0 - Timestamp) * Speed * (float)Godot.Engine.TimeScale;
|
||||||
float duration = GetCurrentPhaseDuration();
|
float duration = GetCurrentPhaseDuration();
|
||||||
return Mathf.Clamp(elapsed / duration, 0f, 1f);
|
return Mathf.Clamp(elapsed / duration, 0f, 1f);
|
||||||
}
|
}
|
||||||
@@ -102,9 +103,10 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
|
|
||||||
private void ResetTimestamp()
|
private void ResetTimestamp()
|
||||||
{
|
{
|
||||||
Timestamp = Time.GetTicksUsec() / 1_000_000.0;
|
Timestamp = Godot.Time.GetTicksUsec() / 1_000_000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Advances the multi-phase attack: dash in, impact, damage/stun application, return and recover.</summary>
|
||||||
protected override bool DoInternalAction()
|
protected override bool DoInternalAction()
|
||||||
{
|
{
|
||||||
float progress = GetPhaseProgress();
|
float progress = GetPhaseProgress();
|
||||||
@@ -258,6 +260,7 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Restores the target's captured position, scale and rotation after the attack animation.</summary>
|
||||||
protected override void DoInternalEnd()
|
protected override void DoInternalEnd()
|
||||||
{
|
{
|
||||||
if (SourceControl != null)
|
if (SourceControl != null)
|
||||||
|
|||||||
@@ -42,9 +42,10 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
public PhysicsDefenceAction(CharacterCardNode source, CharacterCardNode target, ActionCharacter action, float speed = 1)
|
public PhysicsDefenceAction(CharacterCardNode source, CharacterCardNode target, ActionCharacter action, float speed = 1)
|
||||||
: base(source, target, action, speed) { }
|
: base(source, target, action, speed) { }
|
||||||
|
|
||||||
|
/// <summary>Resets the phase clock and captures the target's original scale and colour.</summary>
|
||||||
protected override void DoInternalStart()
|
protected override void DoInternalStart()
|
||||||
{
|
{
|
||||||
Timestamp = Time.GetTicksUsec() / 1_000_000.0;
|
Timestamp = Godot.Time.GetTicksUsec() / 1_000_000.0;
|
||||||
effectApplied = false;
|
effectApplied = false;
|
||||||
phase = ActionPhase.Prepare;
|
phase = ActionPhase.Prepare;
|
||||||
targetOriginalScale = TargetControl.Scale;
|
targetOriginalScale = TargetControl.Scale;
|
||||||
@@ -53,7 +54,7 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
|
|
||||||
private float GetPhaseProgress()
|
private float GetPhaseProgress()
|
||||||
{
|
{
|
||||||
float elapsed = (float)(Time.GetTicksUsec() / 1_000_000.0 - Timestamp) * Speed * (float)Engine.TimeScale;
|
float elapsed = (float)(Godot.Time.GetTicksUsec() / 1_000_000.0 - Timestamp) * Speed * (float)Godot.Engine.TimeScale;
|
||||||
float duration = GetCurrentPhaseDuration();
|
float duration = GetCurrentPhaseDuration();
|
||||||
return Mathf.Clamp(elapsed / duration, 0f, 1f);
|
return Mathf.Clamp(elapsed / duration, 0f, 1f);
|
||||||
}
|
}
|
||||||
@@ -73,9 +74,10 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
|
|
||||||
private void ResetTimestamp()
|
private void ResetTimestamp()
|
||||||
{
|
{
|
||||||
Timestamp = Time.GetTicksUsec() / 1_000_000.0;
|
Timestamp = Godot.Time.GetTicksUsec() / 1_000_000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Advances the guard animation: approach, impact, defence stat application, return and recover.</summary>
|
||||||
protected override bool DoInternalAction()
|
protected override bool DoInternalAction()
|
||||||
{
|
{
|
||||||
float progress = GetPhaseProgress();
|
float progress = GetPhaseProgress();
|
||||||
@@ -196,6 +198,7 @@ namespace Cthangover.CardBattle.Actions
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Restores the target's captured visual state after the defence animation.</summary>
|
||||||
protected override void DoInternalEnd()
|
protected override void DoInternalEnd()
|
||||||
{
|
{
|
||||||
if (SourceControl != null)
|
if (SourceControl != null)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -50,6 +52,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Control GetControlNode() => this;
|
public Control GetControlNode() => this;
|
||||||
|
|
||||||
|
/// <summary>Builds the action card visuals: artwork, name label and point cost chip from the bound ActionCharacter.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -28,6 +30,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// <summary>Container that receives action cards; owned by the input controller.</summary>
|
/// <summary>Container that receives action cards; owned by the input controller.</summary>
|
||||||
public Control Body => _grid;
|
public Control Body => _grid;
|
||||||
|
|
||||||
|
/// <summary>Builds the bottom action bar shown while a card is selected.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -22,6 +24,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
private Label _label;
|
private Label _label;
|
||||||
private Tween _tween;
|
private Tween _tween;
|
||||||
|
|
||||||
|
/// <summary>Builds the centre-screen turn/victory banner label.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.View;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -48,6 +50,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event System.Action<CharacterCardNode> OnCardDead;
|
public event System.Action<CharacterCardNode> OnCardDead;
|
||||||
|
|
||||||
|
/// <summary>Builds the card grid container rows for one battle side.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,6 +21,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
private Label _roundValue;
|
private Label _roundValue;
|
||||||
private Label _enemiesValue;
|
private Label _enemiesValue;
|
||||||
|
|
||||||
|
/// <summary>Builds the battle HUD frame: turn indicator, speed control and log button.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -25,6 +27,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
private ScrollContainer _scroll;
|
private ScrollContainer _scroll;
|
||||||
private VBoxContainer _rows;
|
private VBoxContainer _rows;
|
||||||
|
|
||||||
|
/// <summary>Builds the scrollable battle log with coloured entries per <see cref="BattleLogKind"/>.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
@@ -51,6 +54,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
BattleLogHub.Entry += Append;
|
BattleLogHub.Entry += Append;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Unsubscribes from the shared <see cref="BattleLogHub"/> so the freed panel stops receiving entries.</summary>
|
||||||
protected override void Destruct()
|
protected override void Destruct()
|
||||||
{
|
{
|
||||||
BattleLogHub.Entry -= Append;
|
BattleLogHub.Entry -= Append;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.View;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -48,6 +50,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public CanvasLayer DragLayer { get; private set; }
|
public CanvasLayer DragLayer { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Assembles the full card-battle screen: panels, HUD, banner, log and drag layer.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Cthangover.Core.Cards;
|
using Cthangover.Core.Cards;
|
||||||
using Cthangover.Core.Audio;
|
using Cthangover.Core.Audio;
|
||||||
using Cthangover.Core.Scenes;
|
using Cthangover.Core.Scenes;
|
||||||
@@ -9,6 +9,7 @@ using Cthangover.Core.UI.CharacterPanel;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,6 +71,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
_panels = new[] { screen.PlayerPanel, screen.EnemyPanel };
|
_panels = new[] { screen.PlayerPanel, screen.EnemyPanel };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Routes mouse input into card selection and target picking for the player turn.</summary>
|
||||||
protected override void OnInput(InputEvent @event)
|
protected override void OnInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
if (Cthangover.Core.Battle.BattleSceneContext.Instance != null &&
|
if (Cthangover.Core.Battle.BattleSceneContext.Instance != null &&
|
||||||
@@ -274,7 +276,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
if (source != _selectedCharacter && _selectedCharacter != null)
|
if (source != _selectedCharacter && _selectedCharacter != null)
|
||||||
_selectedCharacter.Unselect();
|
_selectedCharacter.Unselect();
|
||||||
|
|
||||||
var audioService = SceneContextNode.Instance?.GetSceneRoot<AudioService>("AudioService");
|
var audioService = SceneContextNode.Instance?.GetSceneRoot<Node>("AudioService") as IAudioService;
|
||||||
audioService?.PlaySound("battle/card_show_actions", SoundType.CardEffect);
|
audioService?.PlaySound("battle/card_show_actions", SoundType.CardEffect);
|
||||||
|
|
||||||
_selectedCharacter = source;
|
_selectedCharacter = source;
|
||||||
@@ -303,7 +305,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
_currentActionCard.Unselect();
|
_currentActionCard.Unselect();
|
||||||
|
|
||||||
_dragValid = true;
|
_dragValid = true;
|
||||||
var audioService = SceneContextNode.Instance?.GetSceneRoot<AudioService>("AudioService");
|
var audioService = SceneContextNode.Instance?.GetSceneRoot<Node>("AudioService") as IAudioService;
|
||||||
audioService?.PlaySound("battle/card_pick", 4, SoundType.CardEffect);
|
audioService?.PlaySound("battle/card_pick", 4, SoundType.CardEffect);
|
||||||
|
|
||||||
_currentActionCard = source;
|
_currentActionCard = source;
|
||||||
@@ -382,7 +384,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
_originalActionCardParent = null;
|
_originalActionCardParent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var audioService = SceneContextNode.Instance?.GetSceneRoot<AudioService>("AudioService");
|
var audioService = SceneContextNode.Instance?.GetSceneRoot<Node>("AudioService") as IAudioService;
|
||||||
audioService?.PlaySound("battle/card_drop", 4, SoundType.CardEffect);
|
audioService?.PlaySound("battle/card_drop", 4, SoundType.CardEffect);
|
||||||
|
|
||||||
DoActionToTarget();
|
DoActionToTarget();
|
||||||
|
|||||||
@@ -6,13 +6,18 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
|
using Cthangover.Mods.Interface.Theming;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Party or enemy card on the battle field, rebuilt from the interface
|
/// Party or enemy card on the battle field, rebuilt from the interface
|
||||||
/// mockup (mockups/card_battle): full-bleed portrait, team-coloured frame,
|
/// mockup (mockups/card_battle): full-bleed portrait, team-coloured frame,
|
||||||
/// bottom info block with the name, four stat chips (HP/ЗАЩ/АТК/ОД) and an
|
/// bottom info block with the name, four stat chips (HP/ЗАЩ/АТК/ОД) and a
|
||||||
/// HP bar, plus stun badge, zap flash and selection frame in the upper right.
|
/// layered health bar (<see cref="UiKit.StyleShieldedHealthBar"/>:
|
||||||
|
/// track → health fill → blue defence segment drawn past the health edge
|
||||||
|
/// while <see cref="CharacterAttributes.Defence"/> absorbs damage), plus
|
||||||
|
/// stun badge, zap flash and selection frame in the upper right.
|
||||||
/// The node tree lives in <c>scenes/character_card.tscn</c>; this class
|
/// The node tree lives in <c>scenes/character_card.tscn</c>; this class
|
||||||
/// fetches the nodes once, dresses them with <see cref="UiTokens"/> styles and
|
/// fetches the nodes once, dresses them with <see cref="UiTokens"/> styles and
|
||||||
/// exposes the battle-facing API: <see cref="UpdateInfo"/> is the single
|
/// exposes the battle-facing API: <see cref="UpdateInfo"/> is the single
|
||||||
@@ -34,6 +39,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
private TextureRect _art;
|
private TextureRect _art;
|
||||||
private Panel _teamFrame;
|
private Panel _teamFrame;
|
||||||
private Label _nameLabel;
|
private Label _nameLabel;
|
||||||
|
private ProgressBar _shieldBar;
|
||||||
private ProgressBar _hpBar;
|
private ProgressBar _hpBar;
|
||||||
private Label _hpValue;
|
private Label _hpValue;
|
||||||
private Label _defValue;
|
private Label _defValue;
|
||||||
@@ -87,6 +93,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Control GetControlNode() => this;
|
public Control GetControlNode() => this;
|
||||||
|
|
||||||
|
/// <summary>Builds the character card: portrait, art frame, selection overlay and stat labels.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
@@ -94,7 +101,8 @@ namespace Cthangover.CardBattle.UI
|
|||||||
_art = GetNode<TextureRect>("Art");
|
_art = GetNode<TextureRect>("Art");
|
||||||
_teamFrame = GetNode<Panel>("TeamFrame");
|
_teamFrame = GetNode<Panel>("TeamFrame");
|
||||||
_nameLabel = GetNode<Label>("Info/Column/NameLabel");
|
_nameLabel = GetNode<Label>("Info/Column/NameLabel");
|
||||||
_hpBar = GetNode<ProgressBar>("Info/Column/HpBar");
|
_shieldBar = GetNode<ProgressBar>("Info/Column/HpBarStack/ShieldBar");
|
||||||
|
_hpBar = GetNode<ProgressBar>("Info/Column/HpBarStack/HpBar");
|
||||||
_hpValue = GetNode<Label>("Info/Column/Stats/HpChip/Row/Value");
|
_hpValue = GetNode<Label>("Info/Column/Stats/HpChip/Row/Value");
|
||||||
_defValue = GetNode<Label>("Info/Column/Stats/DefChip/Row/Value");
|
_defValue = GetNode<Label>("Info/Column/Stats/DefChip/Row/Value");
|
||||||
_atkValue = GetNode<Label>("Info/Column/Stats/AtkChip/Row/Value");
|
_atkValue = GetNode<Label>("Info/Column/Stats/AtkChip/Row/Value");
|
||||||
@@ -165,8 +173,9 @@ namespace Cthangover.CardBattle.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes every mutable value from the character model: name, HP
|
/// Refreshes every mutable value from the character model: name, layered
|
||||||
/// number and bar (turning red below 40%), defence, attack, action
|
/// HP/defence bar and HP number (health turning red below 40%, blue
|
||||||
|
/// defence segment drawn past the health edge), defence, attack, action
|
||||||
/// points and the stun badge with its remaining turns. Called after each
|
/// points and the stun badge with its remaining turns. Called after each
|
||||||
/// action, on turn start, and by the panel after re-gridding.
|
/// action, on turn start, and by the panel after re-gridding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -180,9 +189,13 @@ namespace Cthangover.CardBattle.UI
|
|||||||
var health = Card.Attributes.Health;
|
var health = Card.Attributes.Health;
|
||||||
var percent = Mathf.Clamp(health.Percent, 0f, 1f);
|
var percent = Mathf.Clamp(health.Percent, 0f, 1f);
|
||||||
_hpBar.Value = percent * 100f;
|
_hpBar.Value = percent * 100f;
|
||||||
_hpBar.AddThemeStyleboxOverride("background", UiKit.Frame(UiTokens.RadiusSm, UiTokens.LineDisabled));
|
|
||||||
_hpBar.AddThemeStyleboxOverride("fill", UiKit.Frame(UiTokens.RadiusSm, percent < 0.4f ? UiTokens.HpLow : UiTokens.HpOk));
|
_hpBar.AddThemeStyleboxOverride("fill", UiKit.Frame(UiTokens.RadiusSm, percent < 0.4f ? UiTokens.HpLow : UiTokens.HpOk));
|
||||||
|
|
||||||
|
// Blue defence segment on top of the health fill; collapses onto
|
||||||
|
// the health edge when the shield is gone.
|
||||||
|
UiKit.UpdateShieldedHealthBar(
|
||||||
|
_shieldBar, percent, Card.Attributes.Defence.Value, health.BaseValue);
|
||||||
|
|
||||||
_hpValue.Text = health.Value + "/" + health.BaseValue;
|
_hpValue.Text = health.Value + "/" + health.BaseValue;
|
||||||
_defValue.Text = Card.Attributes.Defence.Value.ToString();
|
_defValue.Text = Card.Attributes.Defence.Value.ToString();
|
||||||
_atkValue.Text = Card.Attributes.Attack.Value.ToString();
|
_atkValue.Text = Card.Attributes.Attack.Value.ToString();
|
||||||
@@ -269,6 +282,10 @@ namespace Cthangover.CardBattle.UI
|
|||||||
|
|
||||||
_nameLabel.AddThemeColorOverride("font_color", UiTokens.InkBright);
|
_nameLabel.AddThemeColorOverride("font_color", UiTokens.InkBright);
|
||||||
|
|
||||||
|
// Layered pie: the shield bar owns the track and the blue defence
|
||||||
|
// fill; the health bar paints only its fill on top of it.
|
||||||
|
UiKit.StyleShieldedHealthBar(_shieldBar, _hpBar);
|
||||||
|
|
||||||
StyleChip("Info/Column/Stats/HpChip", UiTokens.HpText);
|
StyleChip("Info/Column/Stats/HpChip", UiTokens.HpText);
|
||||||
StyleChip("Info/Column/Stats/DefChip", UiTokens.Ink);
|
StyleChip("Info/Column/Stats/DefChip", UiTokens.Ink);
|
||||||
StyleChip("Info/Column/Stats/AtkChip", UiTokens.Ink);
|
StyleChip("Info/Column/Stats/AtkChip", UiTokens.Ink);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Cthangover.Core.UI;
|
|||||||
using Cthangover.Core.UI.Theming;
|
using Cthangover.Core.UI.Theming;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using Cthangover.Mods.Interface.Base.Lists;
|
||||||
namespace Cthangover.CardBattle.UI
|
namespace Cthangover.CardBattle.UI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,6 +20,7 @@ namespace Cthangover.CardBattle.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event System.Action OnPressed;
|
public event System.Action OnPressed;
|
||||||
|
|
||||||
|
/// <summary>Builds the end-turn button and binds its pressed event.</summary>
|
||||||
protected override void Construct()
|
protected override void Construct()
|
||||||
{
|
{
|
||||||
CthangoverTheme.Apply(this);
|
CthangoverTheme.Apply(this);
|
||||||
|
|||||||
Reference in new issue
Block a user