init
This commit is contained in:
commit
fe403c2dd6
27 files changed
+2675
No files matched your search
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using Cthangover.Core.Mods;
|
||||
using Cthangover.Core.Mods.Resolvers;
|
||||
using Cthangover.Core.Characters;
|
||||
using Cthangover.Core.UI;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.FFBattle.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual representation of a single character (player or enemy) in the FF battle UI.
|
||||
/// Composite widget containing a sprite, HP bar, name label, and selection overlay.
|
||||
/// Supports highlight, flash, shake, and dissolve-death animations via Godot tweens.
|
||||
/// Created per-character by <see cref="FFPlayerPanel.Init"/> and
|
||||
/// <see cref="FFEnemyPanel.Init"/>. Clickable via <c>GuiInput</c> events;
|
||||
/// embedding panels wire these to <see cref="FFBattleCore"/> for action flow.
|
||||
/// </summary>
|
||||
public partial class FFCharacterWidget : ModWidget
|
||||
{
|
||||
private TextureRect _sprite;
|
||||
private TextureRect _selection;
|
||||
private Label _nameLabel;
|
||||
private ColorRect _hpBg;
|
||||
private ColorRect _hpFill;
|
||||
private Tween _animTween;
|
||||
private static Texture2D _cachedSelectTex;
|
||||
private static bool _selectTexLoaded;
|
||||
private static Shader _dissolveShader;
|
||||
|
||||
/// <summary>Whether this widget belongs to the player party (affects highlight/targeting logic).</summary>
|
||||
public bool IsPlayer { get; set; }
|
||||
/// <summary>Whether the character is dead; set by <see cref="PlayDeathAnimation"/>.</summary>
|
||||
public bool IsDead { get; set; }
|
||||
/// <summary>The character data model backing this widget: stats, actions, status effects.</summary>
|
||||
public Character Card { get; set; }
|
||||
/// <summary>Original scale captured at construction; used to restore after death animation.</summary>
|
||||
public Vector2 BaseScale { get; private set; }
|
||||
/// <summary>Exposes this widget as a <see cref="Godot.Control"/> for layout calculations.</summary>
|
||||
public Control ControlNode => this;
|
||||
|
||||
protected override void Construct()
|
||||
{
|
||||
_sprite = GetNode<TextureRect>("Sprite");
|
||||
_hpBg = GetNode<ColorRect>("HpBg");
|
||||
_hpFill = GetNode<ColorRect>("HpFill");
|
||||
_nameLabel = GetNode<Label>("NameLabel");
|
||||
_selection = GetNode<TextureRect>("Selection");
|
||||
|
||||
Size = CustomMinimumSize;
|
||||
|
||||
if (!_selectTexLoaded)
|
||||
{
|
||||
_cachedSelectTex = Textures.Resolve("select");
|
||||
_selectTexLoaded = true;
|
||||
}
|
||||
if (_cachedSelectTex != null)
|
||||
{
|
||||
_selection.Texture = _cachedSelectTex;
|
||||
_selection.ExpandMode = TextureRect.ExpandModeEnum.IgnoreSize;
|
||||
_selection.StretchMode = TextureRect.StretchModeEnum.Scale;
|
||||
_selection.Modulate = new Color(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds this widget to a <see cref="Character"/> model. Sets the sprite from
|
||||
/// <see cref="Character.Image"/>, localises the name via
|
||||
/// <see cref="TranslationServer"/>, and calls <see cref="UpdateInfo"/>
|
||||
/// to refresh the HP bar.
|
||||
/// </summary>
|
||||
public void Init(Character character)
|
||||
{
|
||||
Card = character;
|
||||
BaseScale = Scale;
|
||||
IsDead = false;
|
||||
|
||||
if (_sprite != null && character.Image != null)
|
||||
_sprite.Texture = character.Image;
|
||||
|
||||
if (_nameLabel != null)
|
||||
_nameLabel.Text = TranslationServer.Translate(character.Name);
|
||||
|
||||
UpdateInfo();
|
||||
}
|
||||
|
||||
/// <summary>Refreshes the HP bar fill width and colour gradient based on current health percentage.</summary>
|
||||
public void UpdateInfo()
|
||||
{
|
||||
if (_hpFill == null || Card == null)
|
||||
return;
|
||||
|
||||
var hpPercent = Card.Attributes.Health.Percent;
|
||||
_hpFill.Size = new Vector2((Size.X - 8) * hpPercent, 18);
|
||||
|
||||
if (hpPercent > 0.5f)
|
||||
_hpFill.Color = new Color(0.1f, 0.85f, 0.1f, 1f);
|
||||
else if (hpPercent > 0.25f)
|
||||
_hpFill.Color = new Color(0.85f, 0.85f, 0.1f, 1f);
|
||||
else
|
||||
_hpFill.Color = new Color(0.85f, 0.1f, 0.1f, 1f);
|
||||
}
|
||||
|
||||
/// <summary>Shows a coloured selection overlay with a 0.15s tween fade-in. Used for target highlighting and selection indication.</summary>
|
||||
public void Highlight(Color color)
|
||||
{
|
||||
if (_selection == null)
|
||||
return;
|
||||
|
||||
_animTween?.Kill();
|
||||
_animTween = CreateTween();
|
||||
_animTween.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Quad);
|
||||
_animTween.TweenProperty(_selection, "modulate", color, 0.15f);
|
||||
}
|
||||
|
||||
/// <summary>Fades out the selection overlay to transparent via a 0.15s tween.</summary>
|
||||
public void ClearHighlight()
|
||||
{
|
||||
if (_selection == null)
|
||||
return;
|
||||
|
||||
_animTween?.Kill();
|
||||
_animTween = CreateTween();
|
||||
_animTween.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Quad);
|
||||
_animTween.TweenProperty(_selection, "modulate", new Color(0, 0, 0, 0), 0.15f);
|
||||
}
|
||||
|
||||
/// <summary>Rapidly oscillates the widget's position with random offsets (6 iterations) to simulate impact feedback.</summary>
|
||||
public void Shake(float intensity, float duration)
|
||||
{
|
||||
var originalPos = Position;
|
||||
_animTween?.Kill();
|
||||
_animTween = CreateTween();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var offset = new Vector2(
|
||||
(float)GD.RandRange(-intensity, intensity),
|
||||
(float)GD.RandRange(-intensity, intensity)
|
||||
);
|
||||
_animTween.TweenProperty(this, "position", originalPos + offset, duration / 12f);
|
||||
_animTween.TweenProperty(this, "position", originalPos, duration / 12f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Briefly tints the entire widget with a colour pulse (30% rise, 70% fall) for damage/heal feedback.</summary>
|
||||
public void Flash(Color color, float duration)
|
||||
{
|
||||
var originalModulate = Modulate;
|
||||
_animTween?.Kill();
|
||||
_animTween = CreateTween();
|
||||
_animTween.TweenProperty(this, "modulate", color, duration * 0.3f);
|
||||
_animTween.TweenProperty(this, "modulate", originalModulate, duration * 0.7f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays a dissolve-and-shrink death sequence. If a <c>"scene_transition"</c>
|
||||
/// shader is available, applies a dissolve material to the sprite. Fades the
|
||||
/// widget alpha, scales it to zero, and hides the HP bar and name label.
|
||||
/// Invokes <paramref name="onComplete"/> when finished so the parent panel
|
||||
/// can remove the widget from the grid.
|
||||
/// </summary>
|
||||
public void PlayDeathAnimation(Action onComplete)
|
||||
{
|
||||
if (IsDead)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
IsDead = true;
|
||||
MouseFilter = MouseFilterEnum.Ignore;
|
||||
ClearHighlight();
|
||||
|
||||
_animTween?.Kill();
|
||||
var duration = 0.7f;
|
||||
|
||||
if (_dissolveShader == null)
|
||||
_dissolveShader = Shaders.Resolve("scene_transition");
|
||||
|
||||
if (_dissolveShader != null && _sprite?.Texture != null)
|
||||
{
|
||||
var mat = new ShaderMaterial { Shader = _dissolveShader };
|
||||
mat.SetShaderParameter("noise_scale", 5f);
|
||||
mat.SetShaderParameter("smoothness", 0.25f);
|
||||
mat.SetShaderParameter("distortion", 0.092f);
|
||||
mat.SetShaderParameter("glow_intensity", 0f);
|
||||
mat.SetShaderParameter("hue_shift", 0f);
|
||||
mat.SetShaderParameter("invert_direction", false);
|
||||
mat.SetShaderParameter("progress", 0f);
|
||||
_sprite.Material = mat;
|
||||
|
||||
var matTween = CreateTween();
|
||||
matTween.TweenMethod(
|
||||
Callable.From<float>(t => mat.SetShaderParameter("progress", t)),
|
||||
0f, 1f, duration);
|
||||
}
|
||||
|
||||
var tween = CreateTween();
|
||||
tween.SetParallel(true);
|
||||
tween.TweenProperty(this, "modulate:a", 0f, duration * 0.5f);
|
||||
tween.TweenProperty(this, "scale", BaseScale * new Vector2(0.1f, 1.2f), duration);
|
||||
tween.TweenProperty(_hpBg, "modulate:a", 0f, duration);
|
||||
tween.TweenProperty(_hpFill, "modulate:a", 0f, duration);
|
||||
tween.TweenProperty(_nameLabel, "modulate:a", 0f, duration);
|
||||
|
||||
tween.Chain().TweenProperty(this, "scale", Vector2.Zero, 0.15f);
|
||||
|
||||
tween.Finished += () =>
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user