diff --git a/CBT/FlyText/Animations/FlyTextAnimation.cs b/CBT/FlyText/Animations/FlyTextAnimation.cs
index 9a9dcb2..2659b97 100644
--- a/CBT/FlyText/Animations/FlyTextAnimation.cs
+++ b/CBT/FlyText/Animations/FlyTextAnimation.cs
@@ -3,6 +3,7 @@ namespace CBT.FlyText.Animations;
using System;
using System.Numerics;
+using CBT.FlyText.Configuration;
using CBT.Types;
using FFXIVClientStructs;
@@ -53,29 +54,35 @@ public enum FlyTextAlignment
///
public abstract class FlyTextAnimation
{
+ ///
+ /// When set, animation properties (Duration, Speed, Reversed, Alignment) are read from this config instead of FlyTextKinds.
+ /// Used for Player Damage Taken so it can have different animation settings than Dealt.
+ ///
+ internal FlyTextConfiguration? EventConfig { get; set; }
+
///
/// Gets the Animation duration.
///
public float Duration
- => Service.Configuration.FlyTextKinds[this.FlyTextKind].Animation.Duration;
+ => (this.EventConfig ?? Service.Configuration.FlyTextKinds[this.FlyTextKind]).Animation.Duration;
///
/// Gets the Animation speed.
///
public float Speed
- => Service.Configuration.FlyTextKinds[this.FlyTextKind].Animation.Speed;
+ => (this.EventConfig ?? Service.Configuration.FlyTextKinds[this.FlyTextKind]).Animation.Speed;
///
/// Gets a value indicating whether the animation direction should be reversed.
///
public bool Reversed
- => Service.Configuration.FlyTextKinds[this.FlyTextKind].Animation.Reversed;
+ => (this.EventConfig ?? Service.Configuration.FlyTextKinds[this.FlyTextKind]).Animation.Reversed;
///
/// Gets the alignment of an element.
///
public FlyTextAlignment Alignment
- => Service.Configuration.FlyTextKinds[this.FlyTextKind].Animation.Alignment;
+ => (this.EventConfig ?? Service.Configuration.FlyTextKinds[this.FlyTextKind]).Animation.Alignment;
///
/// Gets or sets the FlyAnimationKind.
@@ -126,17 +133,21 @@ public abstract class FlyTextAnimation
/// Create an instance of a FlyTextAnimation type.
///
/// FlyTextKind determines the animation type.
+ /// Optional config for this event (e.g. Player Damage Taken). When set, animation reads from this instead of FlyTextKinds.
/// FlyTextAnimation implementation.
/// Exception thrown when an invalid kind is received.
- public static FlyTextAnimation Create(FlyTextKind flyTextKind)
+ public static FlyTextAnimation Create(FlyTextKind flyTextKind, FlyTextConfiguration? eventConfig = null)
{
- FlyTextAnimationKind animationKind = Service.Configuration.FlyTextKinds[flyTextKind].Animation.Kind;
- return animationKind switch
+ var config = eventConfig ?? Service.Configuration.FlyTextKinds[flyTextKind];
+ FlyTextAnimationKind animationKind = config.Animation.Kind;
+ FlyTextAnimation animation = animationKind switch
{
FlyTextAnimationKind.None => new None(flyTextKind),
FlyTextAnimationKind.LinearFade => new LinearFade(flyTextKind),
_ => throw new ArgumentOutOfRangeException(nameof(flyTextKind), animationKind, null),
};
+ animation.EventConfig = eventConfig;
+ return animation;
}
///
diff --git a/CBT/FlyText/FlyTextReceiver.cs b/CBT/FlyText/FlyTextReceiver.cs
index d5f9a9f..005b814 100644
--- a/CBT/FlyText/FlyTextReceiver.cs
+++ b/CBT/FlyText/FlyTextReceiver.cs
@@ -94,7 +94,7 @@ public unsafe partial class FlyTextReceiver : IDisposable
{
try
{
- var kindConfig = PluginManager.GetConfigForKind(kind);
+ var kindConfig = PluginManager.GetConfigForEvent(kind, source, target);
var effects = GetEffects(target->GetActionEffectHandler());
var sourceObjectID = GetGameObjectId(target->GetActionEffectHandler());
diff --git a/CBT/Interface/Tabs/KindTab.cs b/CBT/Interface/Tabs/KindTab.cs
index 1f674ac..f6b3ed9 100644
--- a/CBT/Interface/Tabs/KindTab.cs
+++ b/CBT/Interface/Tabs/KindTab.cs
@@ -3,6 +3,7 @@ namespace CBT.Interface.Tabs;
using System.Collections.Generic;
using System.Linq;
using CBT.Types;
+using Dalamud.Bindings.ImGui;
///
/// CatgeoryTab configures settings for FlyTextKinds.
@@ -30,6 +31,23 @@ public class KindTab : Tab
this.DrawCurrentConfigurations(KindPickerValues);
+ if (this.Current.InCategory(FlyTextCategory.AbilityDamage))
+ {
+ GuiArtist.DrawLabelPrefix("Configure for", sameLine: false);
+ ImGui.SameLine();
+ var isTaken = this.UsePlayerDamageTakenConfig;
+ if (ImGui.RadioButton("Player Damage Dealt", !isTaken))
+ {
+ this.UsePlayerDamageTakenConfig = false;
+ }
+
+ ImGui.SameLine();
+ if (ImGui.RadioButton("Player Damage Taken", isTaken))
+ {
+ this.UsePlayerDamageTakenConfig = true;
+ }
+ }
+
if (this.CurrentEnabled)
{
this.DrawFontConfigurations();
diff --git a/CBT/Interface/Tabs/Tab.cs b/CBT/Interface/Tabs/Tab.cs
index df03cf0..3527902 100644
--- a/CBT/Interface/Tabs/Tab.cs
+++ b/CBT/Interface/Tabs/Tab.cs
@@ -27,6 +27,11 @@ public abstract class Tab
///
protected abstract FlyTextKind Current { get; set; }
+ ///
+ /// When true and current kind is AbilityDamage, configuration edits apply to Player Damage Taken instead of Dealt.
+ ///
+ protected bool UsePlayerDamageTakenConfig { get; set; }
+
///
/// Gets or sets a value indicating whether.
///
@@ -235,6 +240,20 @@ public abstract class Tab
///
public abstract void OnClose();
+ ///
+ /// Gets the config dictionary to use for the current kind (FlyTextKinds or FlyTextKindsPlayerDamageTaken for AbilityDamage when editing Taken).
+ ///
+ protected Dictionary GetCurrentConfigDictionary()
+ {
+ if (this.Current.InCategory(FlyTextCategory.AbilityDamage) && this.UsePlayerDamageTakenConfig
+ && Service.Configuration.FlyTextKindsPlayerDamageTaken != null)
+ {
+ return Service.Configuration.FlyTextKindsPlayerDamageTaken;
+ }
+
+ return Service.Configuration.FlyTextKinds;
+ }
+
///
/// Get a configuration value.
///
@@ -243,7 +262,8 @@ public abstract class Tab
/// The value.
protected T GetValue(Func selector)
{
- return Service.Configuration.FlyTextKinds.TryGetValue(this.Current, out var currentConfig)
+ var dict = this.GetCurrentConfigDictionary();
+ return dict.TryGetValue(this.Current, out var currentConfig)
? selector(currentConfig)
: selector(Service.Configuration.FlyTextKinds[this.Current]);
}
@@ -256,10 +276,13 @@ public abstract class Tab
/// The value to set.
protected void SetValue(Action setter, T value)
{
- if (!Service.Configuration.FlyTextKinds.TryGetValue(this.Current, out var currentConfig))
+ var dict = this.GetCurrentConfigDictionary();
+ if (!dict.TryGetValue(this.Current, out var currentConfig))
{
- currentConfig = new FlyTextConfiguration(Service.Configuration.FlyTextKinds[this.Current]);
- Service.Configuration.FlyTextKinds[this.Current] = currentConfig;
+ currentConfig = Service.Configuration.FlyTextKinds.TryGetValue(this.Current, out var baseConfig)
+ ? new FlyTextConfiguration(baseConfig)
+ : new FlyTextConfiguration();
+ dict[this.Current] = currentConfig;
}
setter(currentConfig, value);
@@ -281,7 +304,7 @@ public abstract class Tab
if (this.CurrentEnabled)
{
- if (Service.Configuration.FlyTextKinds.TryGetValue(this.Current, out var currentConfig))
+ if (this.GetCurrentConfigDictionary().TryGetValue(this.Current, out var currentConfig))
{
if (this.Current.ShouldAllow(FlyTextFilter.Self))
{
diff --git a/CBT/Plugin.cs b/CBT/Plugin.cs
index 0d68aa4..d37773f 100644
--- a/CBT/Plugin.cs
+++ b/CBT/Plugin.cs
@@ -3,6 +3,8 @@ namespace CBT;
using System.IO;
using System.Reflection;
using CBT.FlyText;
+using CBT.FlyText.Configuration;
+using CBT.Types;
using CBT.Helpers;
using CBT.Interface;
using Dalamud.Game;
@@ -54,6 +56,7 @@ public sealed partial class Plugin : IDalamudPlugin
ShowInHelp = true,
});
Service.Configuration = pluginInterface.GetPluginConfig() as PluginConfiguration ?? new PluginConfiguration();
+ MigratePlayerDamageTakenConfig();
Service.Fonts = new FontManager(Path.GetDirectoryName(assemblyLocation) + "\\Media\\Fonts\\");
Service.Interface.UiBuilder.OpenConfigUi += this.OnOpenConfigUi;
Service.Interface.UiBuilder.OpenMainUi += this.OnOpenConfigUi;
@@ -88,6 +91,29 @@ public sealed partial class Plugin : IDalamudPlugin
private void OnOpenConfigUi()
=> this.configWindow.IsOpen = true;
+ ///
+ /// Migrates existing config: ensures FlyTextKindsPlayerDamageTaken is populated for AbilityDamage kinds (e.g. from older saves).
+ ///
+ private static void MigratePlayerDamageTakenConfig()
+ {
+ var config = Service.Configuration;
+ if (config.FlyTextKindsPlayerDamageTaken == null || config.FlyTextKindsPlayerDamageTaken.Count == 0)
+ {
+ config.FlyTextKindsPlayerDamageTaken = [];
+ foreach (var kind in FlyTextCategoryExtension.GetKindsFor(FlyTextCategory.AbilityDamage))
+ {
+ if (config.FlyTextKinds.TryGetValue(kind, out var existing))
+ {
+ config.FlyTextKindsPlayerDamageTaken[kind] = new FlyTextConfiguration(existing);
+ }
+ else
+ {
+ config.FlyTextKindsPlayerDamageTaken[kind] = new FlyTextConfiguration();
+ }
+ }
+ }
+ }
+
///
/// OnCommand reacts to commands received via .
///
diff --git a/CBT/PluginConfiguration.cs b/CBT/PluginConfiguration.cs
index 4960013..2e194d6 100644
--- a/CBT/PluginConfiguration.cs
+++ b/CBT/PluginConfiguration.cs
@@ -62,6 +62,12 @@ public class PluginConfiguration : IPluginConfiguration
kind => kind,
kind => new FlyTextConfiguration());
+ this.FlyTextKindsPlayerDamageTaken = FlyTextCategoryExtension
+ .GetKindsFor(FlyTextCategory.AbilityDamage)
+ .ToDictionary(
+ kind => kind,
+ kind => new FlyTextConfiguration());
+
FlyTextCategory.AbilityDamage
.ForEachKind(kind =>
{
@@ -71,6 +77,12 @@ public class PluginConfiguration : IPluginConfiguration
this.FlyTextKinds[kind].Positionals = true;
this.FlyTextKinds[kind].Font.ColorSuccess = new Vector4(0.4f, 1, 0.4f, 1);
this.FlyTextKinds[kind].Font.ColorFailed = new Vector4(1, 0.4f, 0.4f, 1);
+
+ this.FlyTextKindsPlayerDamageTaken[kind].Font.Color = new Vector4(1, 1, 0, 1);
+ this.FlyTextKindsPlayerDamageTaken[kind].Font.Size = 24f;
+ this.FlyTextKindsPlayerDamageTaken[kind].Positionals = true;
+ this.FlyTextKindsPlayerDamageTaken[kind].Font.ColorSuccess = new Vector4(0.4f, 1, 0.4f, 1);
+ this.FlyTextKindsPlayerDamageTaken[kind].Font.ColorFailed = new Vector4(1, 0.4f, 0.4f, 1);
});
FlyTextCategory.AutoAttack
@@ -146,6 +158,27 @@ public class PluginConfiguration : IPluginConfiguration
this.FlyTextKinds[kind].Filter.Self = false;
}
});
+
+ FlyTextCategoryExtension
+ .GetKindsFor(FlyTextCategory.AbilityDamage)
+ .ToList()
+ .ForEach(kind =>
+ {
+ if (kind.ShouldFilter(FlyTextFilter.Party))
+ {
+ this.FlyTextKindsPlayerDamageTaken[kind].Filter.Party = false;
+ }
+
+ if (kind.ShouldFilter(FlyTextFilter.Enemy))
+ {
+ this.FlyTextKindsPlayerDamageTaken[kind].Filter.Enemy = false;
+ }
+
+ if (kind.ShouldFilter(FlyTextFilter.Self))
+ {
+ this.FlyTextKindsPlayerDamageTaken[kind].Filter.Self = false;
+ }
+ });
}
///
@@ -158,6 +191,12 @@ public class PluginConfiguration : IPluginConfiguration
///
public Dictionary FlyTextKinds { get; set; } = [];
+ ///
+ /// Gets or sets the configuration for ability damage when the player is the target (damage taken).
+ /// When the player deals damage, is used; when the player takes damage, this is used.
+ ///
+ public Dictionary FlyTextKindsPlayerDamageTaken { get; set; } = [];
+
///
/// Gets or sets the FlyTextCategory Category Configuration options.
///
diff --git a/CBT/PluginManager.cs b/CBT/PluginManager.cs
index 7f27186..d6edd0d 100644
--- a/CBT/PluginManager.cs
+++ b/CBT/PluginManager.cs
@@ -103,6 +103,26 @@ public unsafe partial class PluginManager
public static FlyTextConfiguration? GetConfigForKind(FlyTextKind kind)
=> Service.Configuration.FlyTextKinds.TryGetValue(kind, out var config) ? config : null;
+ ///
+ /// Get the config for an event. For AbilityDamage kinds, returns Player Damage Taken config when the player is the target, otherwise the normal (Dealt) config.
+ ///
+ /// Kind of the event.
+ /// Source character.
+ /// Target character.
+ /// The configuration to use for this event.
+ public static FlyTextConfiguration? GetConfigForEvent(FlyTextKind kind, Character* source, Character* target)
+ {
+ if (kind.InCategory(FlyTextCategory.AbilityDamage)
+ && target != null
+ && IsPlayerCharacter(target)
+ && Service.Configuration.FlyTextKindsPlayerDamageTaken?.TryGetValue(kind, out var takenConfig) == true)
+ {
+ return takenConfig;
+ }
+
+ return GetConfigForKind(kind);
+ }
+
///
/// Is the target an enemy.
///
diff --git a/CBT/Types/FlyTextEvent.cs b/CBT/Types/FlyTextEvent.cs
index cb335ea..72b76a6 100644
--- a/CBT/Types/FlyTextEvent.cs
+++ b/CBT/Types/FlyTextEvent.cs
@@ -7,6 +7,7 @@ using System.Numerics;
using CBT.FlyText.Animations;
using CBT.FlyText.Configuration;
using CBT.Helpers;
+using CBT;
using Dalamud.Interface.Textures;
using Dalamud.Interface.Textures.TextureWraps;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
@@ -111,14 +112,7 @@ public unsafe partial class FlyTextEvent
{
if (this.configuredOffset == null)
{
- if (Service.Configuration.FlyTextKinds.TryGetValue(this.Kind, out var kindConfig))
- {
- this.configuredOffset = kindConfig.Offset;
- }
- else
- {
- this.configuredOffset = Vector2.Zero;
- }
+ this.configuredOffset = this.Config?.Offset ?? Vector2.Zero;
}
return (Vector2)this.configuredOffset;
@@ -413,8 +407,9 @@ public unsafe partial class FlyTextEvent
// This is a special case for HP Regen attribution.
this.SourceID = sourceID;
- this.Config = new FlyTextConfiguration(kind);
- this.Animation = FlyTextAnimation.Create(kind);
+ var eventConfig = PluginManager.GetConfigForEvent(kind, source, target);
+ this.Config = new FlyTextConfiguration(eventConfig ?? Service.Configuration.FlyTextKinds[kind]);
+ this.Animation = FlyTextAnimation.Create(kind, this.Config);
}
// TODO @cultbaus: I want to use string formatting and text tags instead of this, but for now this can be a placeholder.