@@ -257,6 +267,8 @@
private List ShiftKeys { get; set; } = new();
private KeyData spaceKey = null!;
private KeyData shiftSpaceKey = null!;
+ private string selectedCharacter = "Xavian";
+ private List Characters = [];
public class KeyData
{
@@ -291,57 +303,100 @@
protected override void OnInitialized()
{
- Keys = new List
- {
- new() { Id = "1", Label = "1", SkillName = "Aura of Solace", Character = "Xavian", CooldownDuration = 3 },
- new() { Id = "2", Label = "2" },
- new() { Id = "3", Label = "3" },
- new() { Id = "4", Label = "4" },
- new() { Id = "5", Label = "5" },
- new() { Id = "6", Label = "6" },
- new() { Id = "q", Label = "Q", SkillName = "Shinning Halo", Character = "Xavian", CooldownDuration = 30 },
- new() { Id = "w", Label = "W", SkillName = "Brilliant Flash", Character = "Xavian", CooldownDuration = 0 },
- new() { Id = "e", Label = "E", SkillName = "Move Forward" },
- new() { Id = "r", Label = "R", SkillName = "Sun Strike", Character = "Xavian", CooldownDuration = 0 },
- new() { Id = "t", Label = "T", SkillName = "Sky Crash", Character = "Xavian", CooldownDuration = 60 },
- new() { Id = "a", Label = "A", SkillName = "Solar Shield", Character = "Xavian", CooldownDuration = 15 },
- new() { Id = "s", Label = "S", SkillName = "Move Left" },
- new() { Id = "d", Label = "D", SkillName = "Move Back" },
- new() { Id = "f", Label = "F", SkillName = "Move Right" },
- new() { Id = "g", Label = "G", SkillName = "Blinding Slash", Character = "Xavian", CooldownDuration = 6 },
- new() { Id = "z", Label = "Z" },
- new() { Id = "x", Label = "X" },
- new() { Id = "c", Label = "C" },
- new() { Id = "v", Label = "V", SkillName = "Interupt", Character = "Xavian", CooldownDuration = 12 },
- new() { Id = "b", Label = "B", SkillName = "Taunt", Character = "Xavian", CooldownDuration = 8 }
- };
- spaceKey = new KeyData { Id = "space", Label = "Space", SkillName = "Jump", CooldownDuration = 0.5 };
+ Characters = DocsData.All
+ .OfType()
+ .Where(s => s.Character != null)
+ .Select(s => s.Character!)
+ .Distinct()
+ .Order()
+ .ToList();
- ShiftKeys = new List
+ if (Characters.Count == 0) Characters.Add("Xavian");
+
+ RebuildKeyboardData();
+ }
+
+ private void RebuildKeyboardData()
+ {
+ var skillByKey = DocsData.All
+ .OfType()
+ .Where(s => !string.IsNullOrEmpty(s.Key) && s.Character == selectedCharacter)
+ .GroupBy(s => s.Key!)
+ .ToDictionary(g => g.Key, g =>
+ g.OrderBy(s => string.IsNullOrEmpty(s.CostSwiftReprieval) ? 0 : 1).First());
+
+ var actionByKey = DocsData.All
+ .OfType()
+ .Where(k => !string.IsNullOrEmpty(k.Action))
+ .Select(k => new
+ {
+ Key = Path.GetFileNameWithoutExtension(k.FileName),
+ k.Action
+ })
+ .GroupBy(x => x.Key)
+ .ToDictionary(g => g.Key, g => g.First().Action!, StringComparer.OrdinalIgnoreCase);
+
+ var keyLabels = new[] { "1", "2", "3", "4", "5", "6", "Q", "W", "E", "R", "T", "A", "S", "D", "F", "G", "Z", "X", "C", "V", "B" };
+
+ Keys = keyLabels.Select(label =>
{
- new() { Id = "shift-1", Label = "Shift+1" },
- new() { Id = "shift-2", Label = "Shift+2" },
- new() { Id = "shift-3", Label = "Shift+3" },
- new() { Id = "shift-4", Label = "Shift+4" },
- new() { Id = "shift-5", Label = "Shift+5" },
- new() { Id = "shift-6", Label = "Shift+6" },
- new() { Id = "shift-q", Label = "Shift+Q", SkillName = "Decree of the Sun", Character = "Xavian", CooldownDuration = 0 },
- new() { Id = "shift-w", Label = "Shift+W" },
- new() { Id = "shift-e", Label = "Shift+E" },
- new() { Id = "shift-r", Label = "Shift+R", SkillName = "Omnistrike", Character = "Xavian", CooldownDuration = 18 },
- new() { Id = "shift-t", Label = "Shift+T" },
- new() { Id = "shift-a", Label = "Shift+A" },
- new() { Id = "shift-s", Label = "Shift+S" },
- new() { Id = "shift-d", Label = "Shift+D" },
- new() { Id = "shift-f", Label = "Shift+F" },
- new() { Id = "shift-g", Label = "Shift+G", SkillName = "Solar Blades", Character = "Xavian", CooldownDuration = 9 },
- new() { Id = "shift-z", Label = "Shift+Z" },
- new() { Id = "shift-x", Label = "Shift+X" },
- new() { Id = "shift-c", Label = "Shift+C" },
- new() { Id = "shift-v", Label = "Shift+V" },
- new() { Id = "shift-b", Label = "Shift+B" }
+ var skill = skillByKey.GetValueOrDefault(label);
+ var action = actionByKey.GetValueOrDefault(label);
+ var skillName = skill != null ? Path.GetFileNameWithoutExtension(skill.FileName) : action;
+ return new KeyData
+ {
+ Id = label.ToLower(),
+ Label = label,
+ SkillName = skillName,
+ Character = skill?.Character,
+ CooldownDuration = ParseCooldown(skill?.Cooldown)
+ };
+ }).ToList();
+
+ var spaceSkill = skillByKey.GetValueOrDefault(" ");
+ var spaceAction = actionByKey.GetValueOrDefault("Space");
+ spaceKey = new KeyData
+ {
+ Id = "space",
+ Label = "Space",
+ SkillName = spaceSkill != null ? Path.GetFileNameWithoutExtension(spaceSkill.FileName) : spaceAction,
+ Character = spaceSkill?.Character,
+ CooldownDuration = ParseCooldown(spaceSkill?.Cooldown)
};
- shiftSpaceKey = new KeyData { Id = "shift-space", Label = "Shift+Space" };
+
+ ShiftKeys = keyLabels.Select(label =>
+ {
+ var shiftKeyStr = "Shift + " + label;
+ var skill = skillByKey.GetValueOrDefault(shiftKeyStr);
+ var action = actionByKey.GetValueOrDefault(shiftKeyStr);
+ var skillName = skill != null ? Path.GetFileNameWithoutExtension(skill.FileName) : action;
+ return new KeyData
+ {
+ Id = "shift-" + label.ToLower(),
+ Label = "Shift+" + label,
+ SkillName = skillName,
+ Character = skill?.Character,
+ CooldownDuration = ParseCooldown(skill?.Cooldown)
+ };
+ }).ToList();
+
+ var shiftSpaceSkill = skillByKey.GetValueOrDefault("Shift + Space");
+ var shiftSpaceAction = actionByKey.GetValueOrDefault("Shift + Space");
+ shiftSpaceKey = new KeyData
+ {
+ Id = "shift-space",
+ Label = "Shift+Space",
+ SkillName = shiftSpaceSkill != null ? Path.GetFileNameWithoutExtension(shiftSpaceSkill.FileName) : shiftSpaceAction,
+ Character = shiftSpaceSkill?.Character,
+ CooldownDuration = ParseCooldown(shiftSpaceSkill?.Cooldown)
+ };
+ }
+
+ private static double ParseCooldown(string? cooldown)
+ {
+ if (string.IsNullOrEmpty(cooldown)) return 0;
+ if (double.TryParse(cooldown, out var result)) return result;
+ return 0;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -385,6 +440,7 @@
private void ActivateKey(KeyData key)
{
if (key.OnCooldown) return;
+ if (key.Character == null) return;
var duration = key.CooldownDuration > 0 ? key.CooldownDuration : 0.5;
key.Remaining = duration;
diff --git a/Fellowship/Web/Pages/Keyboard.razor.css b/Fellowship/Web/Pages/Keyboard.razor.css
index 6666475..58dd6b0 100644
--- a/Fellowship/Web/Pages/Keyboard.razor.css
+++ b/Fellowship/Web/Pages/Keyboard.razor.css
@@ -120,6 +120,41 @@
text-shadow: 0 0 4px rgba(0, 0, 0, 0.8);
}
+.character-selector {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 16px;
+ padding: 10px 20px;
+ background: #1a1a1a;
+ border: 1px solid #2a2a2a;
+ border-radius: 8px;
+}
+
+.character-selector label {
+ font-size: 13px;
+ font-weight: 600;
+ color: #888;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+}
+
+.character-selector select {
+ padding: 6px 12px;
+ border: 1px solid #333;
+ border-radius: 6px;
+ background: #0f0f0f;
+ color: #e0e0e0;
+ font-size: 14px;
+ outline: none;
+ cursor: pointer;
+}
+
+.character-selector select:focus {
+ border-color: #5588ff;
+ box-shadow: 0 0 0 3px rgba(85, 136, 255, 0.15);
+}
+
.kb-divider {
color: #888;
font-size: 14px;