-
Notifications
You must be signed in to change notification settings - Fork 162
Support Spectres and Companions, and overhaul Spectre Library #936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AI REVIEW BELOW:
- 75mins worth of opus4 compute time was used -> with the goal to document the Specter Library changes and review them. Again, everything below is ai generated, tread lightly (still worth reading):
📈 Overall Assessment
This is an impressive, well-executed feature addition. The issues found are mostly safety/polish concerns rather than fundamental problems. The architecture is sound and the implementation follows PoB conventions well.
Recommendation: Merge after confirming the life table change is intentional and adding nil checks. Other issues can be addressed in follow-up PRs.
Technical Documentation: Spectres & Companions Implementation
High-Level Architecture
Core Concept
Spectres and Companions are implemented as special minion types that can be selected from a library of 927 pre-defined monsters. They integrate seamlessly with the existing minion system while adding their own unique mechanics.
Key Components
-
Skill Identification
- Skills starting with
^Spectre:
are identified as spectre skills - Skills starting with
^Companion:
are identified as companion/beast skills - This allows the system to handle them differently from regular minions
- Skills starting with
-
Data Structure
-- Each spectre/companion has: { name = "Monster Name", life = 1000, energyShield = 0, armour = 300, spectreReservation = 50, -- Calculated value companionReservation = 30, -- Calculated value monsterCategory = "Beast", spawnLocation = {"The Coast", "The Ledge"}, skillList = {"MeleeAtAnimationSpeed", "Leap"}, -- ... more stats }
-
Reservation Formulas
- Spectres:
50 * ExperienceMultiplier
, rounded to nearest 10 - Companions:
round(sqrt(ExperienceMultiplier/100), 2) * 30
- Spectres:
Detailed Implementation
UI Flow (MinionListControl)
-
Library Selection
- User clicks "Spectre Library" or "Companion Library" button
- Opens MinionListControl in appropriate mode
-
Filtering System
-- Monster type checkboxes: - Eldritch - Undead - Demon - Construct - Humanoid - Beast - Show All
-
Search & Sort
- Real-time search across monster names
- Sort by: Name, Life, Spirit Reservation, Combined HP, ES+Life+Armour
-
Selection Process
- User selects monster from filtered/sorted list
- System updates
gemInstance.skillMinion
with monster ID - Skill gem name updates to show selected monster
Calculation Integration
-
Life Calculation
- Uses
monsterAllyLifeTable
instead ofmonsterLifeTable
- Scales with minion life modifiers
- Uses
-
Reservation Calculation
- Integrates with existing reservation system
- Uses
round
instead ofm_ceil
for percentage-based reservations
-
Stat Inheritance
- Spectres inherit applicable minion modifiers
- Energy shield calculation:
Type.EnergyShield / 100
(no 0.4 multiplier)
Data Management
-
Export Process
Export/Scripts/minions.lua → Data/Minions.lua Export/Scripts/spectreList.lua → Data/Spectres.lua Export/Scripts/worldAreas.lua → Data/WorldAreas.lua
-
Save Format
- Only stores spectre/companion ID in builds
- Full data loaded from static files at runtime
- Minimizes save file size
Import/Export Support
-
Build Sharing
- Spectre selections preserved in build codes
- Graceful handling of missing spectres in older PoB versions
-
Validation
- Checks if selected spectre ID exists in data
- Falls back to default if invalid
Maintenance Guide
Adding New Spectres
- Update
Export/Scripts/spectreList.lua
with new monster data - Ensure ExperienceMultiplier is set for reservation calculation
- Add appropriate skills to skill definitions
- Regenerate data files by running export scripts
- Test reservation calculations match in-game values
Modifying Formulas
- Edit formulas in
Export/Scripts/minions.lua
- Regenerate
Data/Minions.lua
- Test with known examples (Dread Servant, Faridun Impaler, etc.)
Debugging Tips
- Check
skillMinion
ID matches entries indata.spectres
- Verify WorldAreas is loaded if spawn locations crash
- Ensure round() function is available in environment
- Monitor performance with large spectre lists
This PR successfully implements a complete spectre/companion system with 927 spectres, proper UI integration, and formula-based reservation calculations. The implementation is well-architected and maintains backward compatibility.
✅ Excellent Implementation
Architecture & Code Quality
- Clean separation using
^Spectre:
and^Companion:
skill patterns - Excellent reuse of existing minion infrastructure
- Well-structured MinionListControl with filtering and sorting
- Proper data/UI/logic separation across modules
Data & Formulas
- 927 spectres with comprehensive stats and spawn locations
- Correct formula implementation in
minions.lua
:spectreReservation = round(50 * math.max(monsterVariety.ExperienceMultiplier/100, 0) / 10) * 10 companionReservation = round(math.sqrt(monsterVariety.ExperienceMultiplier/100), 2) * 30
🔍 Issues Requiring Attention
Should Fix Before Merge:
-
Life Table Change
- Changed from
monsterLifeTable
tomonsterAllyLifeTable
- This will significantly change spectre HP values
- Please confirm this is intentional to match game mechanics
- Changed from
-
Missing nil checks
data.spectres[gemInstance.skillMinion]
accessed without validationself.data.minions[selected]
in UpdateMinionDisplay- Add defensive checks to prevent crashes
-
Round function availability
- Uses
round(value, 2)
but Lua doesn't have this natively - Confirm it's defined in PoB's Common.lua or add implementation
- Uses
-
WorldAreas loading
data.worldAreas = {}
declared but LoadModule not visible in diff- If not loaded elsewhere, tooltips will crash accessing spawn locations
Data Verification:
-
Faridun Impaler discrepancy
- Has spectreReservation = 110
- Your example: 50 * 2.30 = 115 → 120
- Please verify the ExperienceMultiplier value
-
Energy Shield calculation (chunk 12)
- Changed from
0.4 * Type.EnergyShield / 100
toType.EnergyShield / 100
- 2.5x increase - please confirm if matching game changes
- Changed from
📊 Performance Considerations
With 927 spectres, consider:
- Search debouncing (100-200ms) to avoid lag
- Lookup tables for O(1) name→ID access
- List virtualization for large dropdowns
📝 ModCache.lua Note
Important: If you modified mod parsing logic, ensure you've regenerated ModCache.lua with Ctrl+F5. We couldn't verify this from the diff alone.
🔄 Intentional Changes Acknowledged
Per your PR description:
- Rounding change from
m_ceil
toround
for percentage reservations (PR #725 related) - Formula: rounds to nearest 10, not always up
- Both changes appear correctly implemented
Fixes #930 .
https://docs.google.com/spreadsheets/d/1oadXSCHczpyCgRxzTk3nRBeeOLlefZAzKM3ijwmWevY/edit?gid=0#gid=0
From Reddit and a Youtuber Truditoru. Could be very handy
Description of the problem being solved:
Spectre library did not show, so quick from from @LocalIdentity got it working. Still some smaller bugs, but for now getting some initial spectres in is important.
Exported the experience multiplier and monster category to minions and spectres. The category will be needed for Tame Beast/Companion.
Most skills included. Vaal Guard's skills are similar to player skills that haven't been fully implemented yet either. So when they are updated, Vaal Guard can be too.
Spectre gem costs 50 spirit always. It should be 50 * Monster experience multiplier, rounded to nearest 10. Eg, Dread Servant is 50 * 1.50 = 75. Rounded up to 80 to match in game. Same with Faridun Impaler and Filthy Crone. Both are 50 * 2.30 = 115. In game, both are 120.
https://poe2db.tw/us/Terracotta_Soldier#TerracottaSoldierTerracottaGuardianSceptreAmbush__
This one rounds down to 10 Spirit in game. But PoE2DB shows it as 20 on the site. So I believe the formula just rounds to nearest 10, not round up to nearest 10.
Issues:
EDIT: Tame Beast formula is
round(Sqrt(MonsterExperience/100),2) * 30
Adding to the Companion formula. In game it appears to round normally. with 176 spirit, spirit shaman reserves 75 spirit in game. PR #725 changed rounding for both flat and percentage. The issue it closed was for flat, so maybe it's safe to change percentage rounding back to normal? If not, we will have to separate the calcs. For now I returned it to normal rounding.
After screenshot: