Elin
Tome of Memory Loss
Showing 1-10 of 13 entries
< 1  2 >
Update: 7 Sep @ 12:36am

THE BUG:
- Two systems conflicted: innate abilities (from race/job data) and learned spells (from the element system).
- Tracking spell removals needed to survive both game reloads and ability refresh calls.
- Re-learning detection was broken: if a spell was removed and later learned again, it stayed invisible.

THE CORE PROBLEMS:

1. "Ghost Spell" Bug: Removed spell → NPC learned it again → spell stayed invisible in the tome UI.
2. Innate vs Learned Detection: The same spell could be both innate and learned at once.
3. Refresh Persistence: CharaAbility.Refresh() would undo removals and restore spells.

THE HOTFIX:

1. Hybrid Detection System

- Old approach: Directly used source data, which meant innate abilities could never be removed.
- New approach: Read abilities from `list.items`, but classify correctly:
- Learned abilities → check `_listAbility` and use real charges from `chara.elements`.
- Innate abilities → classified with no fake charges.

------------------------------------------------------------------------
// AFTER: Hybrid classification
bool isLearned = IsInLearnedList(chara, spell.id);
if (isLearned) {
element = chara.elements.GetElement(spell.id);
} else {
element = null; // Innate ability
}
------------------------------------------------------------------------

2. PersistentAbilityTracker with Re-Learning Detection

* Added removal tracking that persists across refreshes and reloads.
* When Refresh is called:
* If a spell should stay removed but is found in `chara.elements.dict`, it means the NPC actually re-learned it. In that case, we stop tracking removal.
* Otherwise, the removal persists.

------------------------------------------------------------------------
if (PersistentAbilityTracker.ShouldRemainRemoved(chara, spell.id)) {
if (chara.elements.dict.ContainsKey(spell.id)) {
PersistentAbilityTracker.UntrackRemoval(chara, spell.id);
} else {
__instance.list.items.RemoveAt(i);
}
}
------------------------------------------------------------------------

3. Cross-Mod Synchronization

* Used `BaseCard.mapObj` for persistence and cross-mod sync.
* Shared a unique storage key so NPCSpellFix and CustomAI always stay in sync.

------------------------------------------------------------------------
private const int MAGIC_NUMBER = 1337420069;
((BaseCard)chara).SetObj(MAGIC_NUMBER, removedAbilities);
------------------------------------------------------------------------

KEY ELIN CLASSES INVOLVED:

* `CharaAbility.Refresh()` – patched to keep removals intact.
* `chara.elements.dict` – holds learned spells and charges.
* `chara.ability.list.items` – the actual combat ability list.
* `chara._listAbility` – the internal learned ability list.
* `BaseCard.SetObj/GetObj<T>()` – persistence system for saving removals.
* `PersistentAbilityTracker` – custom tracker that makes the system reliable.

RESULT:

* Innate abilities can now be removed permanently.
* Learned spells show proper charges and are manageable.
* Re-learned spells reappear automatically.
* NPCSpellFix and CustomAI stay perfectly synchronized.
* Persistence works across saves and reloads.

Update: 7 Sep @ 12:09am

New config to show the list of configs in the Spell display, default off

Update: 6 Sep @ 11:51pm

fixes regressions:
NPCSpellManager.cs changes:
1. Fixed learned vs innate detection
- Root cause was NPCSpellFix creating fake elements that made everything look "learned".

2. Restored removal functionality
- Implemented hybrid approach reading from ability.list.items with smart classification.

3. Added IsInLearnedList() helper
- Checks _listAbility to distinguish truly learned from innate abilities.

Update: 6 Sep @ 8:00pm

NPCSpellManager v4 - Charge Display

Fixed synchronization issues by switching to ability.list.items approach:

* Why this works: ability.list.items is the live ability list that NPCSpellFix modifies when removing depleted spells
* Previous approach: Read from dual sources (elements + hardcoded abilities) causing desync when NPCSpellFix removed spells
* New approach: Single source matching CustomAI's method ensures perfect synchronization
* Charge Display: Added format showing charges for learned spells: "Spell Name (level, 5c)"
* Result: When learned spells are depleted, they disappear instantly from both CustomAI and SpellManager

Update: 5 Sep @ 12:55am

Updated with 2 new default option:
- PreventEnemyRemoval = true - Blocks spell/ability removal from hostile NPCs
- PreventEnemyMenuAccess = true - Shows menu option but provides flavor text refusal for enemies

Increased cost by ~10k value (~9 gold bar in my game after all calculations). Can set this in the Excel sheet

Update: 4 Sep @ 6:35pm

Issue: Ability removals were lost on save/reload and NPC spellbook interactions

Root Cause: Game’s CharaAbility.Refresh() rebuilds ability lists from scratch, ignoring temporary tracking data

Fix:
* Removed abilities are now stored directly on characters using the game’s save system
* Patched CharaAbility.Refresh() to automatically re-remove tracked abilities

Technical Details:
* Uses Elin’s built-in character serialization system

Update: 4 Sep @ 12:11am

Fixed all documented issues:
* Golden Knight and other NPC innate spell detection (hardcoded abilities now visible)
* NPC-specific compatibility issues (dual-system detection works universally)
* Removal crashes (proper null checking and system coordination)
* Index synchronization bugs (fresh data fetching on operations)


Technical info:

1. Learned Abilities
- Stored in `chara.elements.dict` and `chara._listAbility`
- Added by mods like NPC Spell Learning
- Visible to standard detection methods
- Removable via `elements.Remove()`

2. Hardcoded Abilities
- Stored in `source.actCombat`, processed through `CharaAbility.Refresh()`
- Examples: Golden Knight's *Rush*, *Taunt*, *Nature's Embrace*
- NOT stored in `elements.dict` → invisible to legacy detection
- Processed via `ActList.Item` objects in `chara.ability.list.items

Update: 3 Sep @ 12:30am

Fixed crash when removing spell due to regression in spell removal logic

Update: 2 Sep @ 7:56pm

- Universal spell/ability detection (IsSpellLikeElement()) - catches all variants
- Direct element ID removal (RemoveElementById()) - bypasses source lookup failures
- Proper charge depletion protection - blocks actions with clear messages

Update: 31 Aug @ 2:27am

minor typo (correct "Right click" to "Middle click" in game descriptions)