Initial release: HSCompare v1.0.2 - WoW-style equipment comparison tooltips
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# HSCompare Plugin – Layout and Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
HSCompare is a Dalamud plugin for FFXIV that **replaces or augments equipment tooltips** with a comparison view. When the user hovers over an equipment item (armor/weapon) and holds a configurable modifier key (default: Shift), the plugin shows:
|
||||
|
||||
1. **Hovered item** – the item under the cursor
|
||||
2. **Currently equipped item** – the item in the same equipment slot
|
||||
3. **Total stat difference** – below the tooltip, showing the net stat change if the hovered item were equipped (WoW-style: green for gains, red for losses)
|
||||
|
||||
If the hovered item is already equipped, or the item is not equipment, the default game tooltip behavior is unchanged (no replacement).
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Components
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|--------|
|
||||
| **Plugin.cs** | Entry point. Subscribes to `IGameGui.HoveredItemChanged`, registers `/hscompare` command, injects services, and draws UI each frame. |
|
||||
| **Configuration.cs** | Persisted settings: modifier key (VirtualKey), tooltip font size, comparison window size (width/scale). |
|
||||
| **PluginUI.cs** | ImGui logic: draws comparison window when conditions are met, applies font/size from config; config window is in the same class. |
|
||||
| **ItemBonusType.cs** | Enum of FFXIV base param IDs with display names (Strength, Vitality, etc.). |
|
||||
|
||||
### Data Flow
|
||||
|
||||
1. **Hover** → `IGameGui.HoveredItemChanged` fires with item ID (and HQ flag via offset 1_000_000).
|
||||
2. **Resolve item** → `IDataManager.GetExcelSheet<Item>().GetRow(itemId)` → `Item` + HQ flag → wrapped as `InvItem`.
|
||||
3. **Is equipment?** → `Item.EquipSlotCategory` non-null and not “none” (e.g. MainHand, Head, Body).
|
||||
4. **Map to slot** → `EquipSlotCategory` → FFXIVClientStructs `InventoryType` (e.g. ArmoryMainHand, ArmoryHead).
|
||||
5. **Get equipped** → `InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems)`, scan by slot; get `Item` for same slot.
|
||||
6. **Compare** → Only show comparison if hovered item is **not** the same as equipped (different RowId or slot). Build stat maps for both items (base params + defense/damage/block), then diff.
|
||||
7. **Key check** → Each frame in Draw: `IKeyState[Configuration.ModifierKey]` (or fallback to Win32 `GetKeyState` for the configured VK). Only show comparison window when key is held.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Tooltip “replacement”
|
||||
|
||||
- The game’s own tooltip is **not** suppressed (no public Dalamud API to hide it). The plugin draws an **additional** ImGui window when comparison is active.
|
||||
- **Layout**: One window or two side-by-side:
|
||||
- **Left**: Hovered item (name, ilvl, main stats, substats).
|
||||
- **Right**: “Currently Equipped” (same fields).
|
||||
- **Below** (or bottom section of same window): “If you replace this item, the following stat changes will occur:” then list of stat deltas (e.g. “+12 Strength”, “-5 Critical Hit”) in green/red.
|
||||
- Position: near cursor or below default tooltip (e.g. cursor + offset so the comparison appears below the game tooltip).
|
||||
|
||||
### 2. Modifier key (configurable)
|
||||
|
||||
- **Config**: Store `VirtualKey` (e.g. `VirtualKey.SHIFT`). Default: Shift.
|
||||
- **Runtime**: In `PluginUI.Draw()`, check `IKeyState[config.ModifierKey]`. If not pressed, do not draw comparison.
|
||||
- **Config UI**: Dropdown or key selector for modifier (list common: Shift, Ctrl, Alt).
|
||||
|
||||
### 3. Font and window size (configurable)
|
||||
|
||||
- **Font**: `ImGui.GetIO().Fonts` – push a scaled font (e.g. `ImGui.GetFont()->FontSize * config.TooltipFontScale`) before drawing the comparison window; pop after.
|
||||
- **Window size**: `ImGui.SetWindowSize()` or use `ImGuiWindowFlags.AlwaysAutoResize` and control width via `ImGui.PushItemWidth()` / text wrap width, or store a “max width” in config and use it for wrapping. Alternatively, a simple “scale” factor that scales both font and padding.
|
||||
|
||||
### 4. Stat difference (total change when equipping hovered item)
|
||||
|
||||
- **Meaning**: “Total stat change” = (hovered item stats) − (equipped item stats). Positive = gain if you equip hovered, negative = loss.
|
||||
- **Sources for stats**:
|
||||
- **Substats**: `Item.UnkData59` (BaseParam, BaseParamValue). If HQ, add `Item.UnkData73` (BaseParamValueSpecial) for the same BaseParamSpecial.
|
||||
- **Main stats**: Defense (Phys/Mag), Damage (Phys/Mag), Block, BlockRate from `Item` (mapped into the same “bonus” map by type, as in SimpleCompare).
|
||||
- **Display**: One line per stat that has a non-zero delta: “+12 Strength”, “-5 Critical Hit”, “-0.7 Damage Per Second” (if we compute DPS or just “Physical Damage”). Use `ImGui.ColoredText` green for positive, red for negative.
|
||||
- **Materia**: Optional: show materia slot count difference (e.g. “+1 Materia slot”).
|
||||
|
||||
### 5. Equipment slot mapping
|
||||
|
||||
- Use `Item.EquipSlotCategory.Value` (Lumina): MainHand, OffHand, Head, Body, Hands, Waist, Legs, Feet, Ears, Neck, Wrists, FingerL, FingerR, SoulCrystal.
|
||||
- Map to `FFXIVClientStructs.FFXIV.Client.Game.InventoryType`: ArmoryMainHand, ArmoryOffHand, ArmoryHead, ArmoryBody, ArmoryHands, ArmoryWaist, ArmoryLegs, ArmoryFeets, ArmoryEar, ArmoryNeck, ArmoryWrist, ArmoryRings (both fingers), ArmorySoulCrystal.
|
||||
- **Rings**: Two slots; we compare against “the slot this item would go in” – e.g. first ring slot that matches. Simple approach: compare hovered to both equipped rings and show the one that matches slot or the first.
|
||||
|
||||
### 6. Edge cases
|
||||
|
||||
- **Soul crystal / non-equipment**: Ignore (no comparison).
|
||||
- **Same item equipped**: If hovered item RowId equals equipped item RowId, optionally hide comparison or show “No change”.
|
||||
- **Empty slot**: If nothing equipped in that slot, show only hovered item and “Currently equipped: (empty)” with stat list = hovered item’s stats as gains.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
HSCompare/
|
||||
├── HSCompare.sln
|
||||
├── HSCompare/
|
||||
│ ├── HSCompare.csproj
|
||||
│ ├── HSCompare.json # Manifest template for DalamudPackager
|
||||
│ ├── Plugin.cs
|
||||
│ ├── Configuration.cs
|
||||
│ ├── PluginUI.cs
|
||||
│ ├── ItemBonusType.cs
|
||||
└── PLUGIN_LAYOUT.md # This file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Dalamud** (via `$(DalamudLibPath)`): Dalamud.dll, ImGui.NET.dll, ImGuiScene.dll, Lumina.dll, Lumina.Excel.dll, Newtonsoft.Json.dll.
|
||||
- **FFXIVClientStructs**: For `InventoryManager`, `InventoryType`, `InventoryItem` (equipped item IDs and HQ flag).
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Requirement | Implementation |
|
||||
|-------------|----------------|
|
||||
| Replace/augment equipment tooltips | Draw ImGui comparison window when modifier held and hovered item is equipment. |
|
||||
| Compare to equipped when not equipped | Resolve slot from `EquipSlotCategory`, read equipped from `InventoryManager`, show both. |
|
||||
| Configurable key | Configuration.ModifierKey (VirtualKey), checked via IKeyState. |
|
||||
| Configurable font and window size | Config: font scale and/or window width; apply in PluginUI before drawing. |
|
||||
| Total stat difference below tooltip | Section “If you replace this item…” with (hovered − equipped) deltas, green/red. |
|
||||
| WoW-like comparison | Two blocks (hovered | equipped) + stat change list; color-coded. |
|
||||
|
||||
This layout keeps the plugin modular, testable, and aligned with existing Dalamud and SimpleCompare patterns.
|
||||
Reference in New Issue
Block a user