fix(v2): character window — verbatim property ID maps from v1

Property ID maps were wrong (made-up IDs 360-390). Now uses the
exact same IDs as v1 script.js lines 1843-1876:

- TS_AUGMENTATIONS: IDs 218-328 (30 augmentations)
- TS_AURAS: IDs 333-365 (11 luminance auras)
- TS_RATINGS: IDs 370-379 (8 ratings)
- TS_SOCIETY: IDs 287-289 (3 societies)
- TS_MASTERIES: IDs 354-362 with TS_MASTERY_NAMES lookup
- TS_GENERAL: IDs 181-390 (chess, fishing, total augs, aetheria, enlightenment)
- societyRank() function matching v1's _tsSocietyRank()

Other tab now shows General + Masteries + Society sections (was
only showing allegiance). Each section has its own header matching
v1's ts-section-title styling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-12 22:35:30 +02:00
parent bd8ad863d1
commit b00c386d77
4 changed files with 189 additions and 139 deletions

View file

@ -4,15 +4,47 @@ import { apiFetch } from '../../api/client';
interface Props { id: string; charName: string; zIndex: number; vitals?: any; }
// Property ID maps matching v1's TS_AUGMENTATIONS, TS_AURAS, TS_RATINGS, etc.
// Property ID maps — verbatim from v1 script.js lines 1843-1876
const TS_AUGMENTATIONS: Record<number, string> = {
369:'Blade Turner',370:'Arrow Turner',371:'Mace Turner',
372:'Caustic Enhancement',373:'Fiery Enhancement',374:'Icy Enhancement',375:'Lightning Enhancement',
376:'Critical Protection',377:'Frenzy',362:'Iron Skin',363:'Eye of the Remorseless',364:'Hand of the Remorseless',
365:'Ciandra\'s Essence',366:'Yoshi\'s Essence',367:'Jibril\'s Essence',368:'Celdiseth\'s Essence',
218:'Reinforcement of the Lugians',219:"Bleeargh's Fortitude",220:"Oswald's Enhancement",
221:"Siraluun's Blessing",222:'Enduring Calm',223:'Steadfast Will',
224:"Ciandra's Essence",225:"Yoshi's Essence",226:"Jibril's Essence",
227:"Celdiseth's Essence",228:"Koga's Essence",229:'Shadow of the Seventh Mule',
230:'Might of the Seventh Mule',231:'Clutch of the Miser',232:'Enduring Enchantment',
233:'Critical Protection',234:'Quick Learner',235:"Ciandra's Fortune",
236:'Charmed Smith',237:'Innate Renewal',238:"Archmage's Endurance",
239:'Enhancement of the Blade Turner',240:'Enhancement of the Arrow Turner',
241:'Enhancement of the Mace Turner',242:'Caustic Enhancement',243:'Fierce Impaler',
244:'Iron Skin of the Invincible',245:'Eye of the Remorseless',246:'Hand of the Remorseless',
294:'Master of the Steel Circle',295:'Master of the Focused Eye',
296:'Master of the Five Fold Path',297:'Frenzy of the Slayer',
298:'Iron Skin of the Invincible',299:'Jack of All Trades',
300:'Infused Void Magic',301:'Infused War Magic',
302:'Infused Life Magic',309:'Infused Item Magic',
310:'Infused Creature Magic',326:'Clutch of the Miser',
328:'Enduring Enchantment',
};
const TS_AURAS: Record<number, string> = { 378:'Valor',379:'Protection',380:'Glory',381:'Temperance',382:'Aetheric Vision',383:'Mana Flow',384:'Mana Infusion',385:'Purity',386:'Craftsman',387:'Specialization',388:'World' };
const TS_RATINGS: Record<number, string> = { 354:'Damage Rating',355:'Damage Resist Rating',356:'Crit Rating',357:'Crit Resist Rating',358:'Crit Damage Rating',359:'Crit Damage Resist Rating',360:'Heal Boost Rating',361:'Vitality Rating' };
const TS_AURAS: Record<number, string> = {
333:'Valor / Destruction',334:'Protection',335:'Glory / Retribution',
336:'Temperance / Hardening',338:'Aetheric Vision',339:'Mana Flow',
340:'Mana Infusion',342:'Purity',343:'Craftsman',344:'Specialization',365:'World',
};
const TS_RATINGS: Record<number, string> = {
370:'Damage',371:'Damage Resistance',372:'Critical',373:'Critical Resistance',
374:'Critical Damage',375:'Critical Damage Resistance',376:'Healing Boost',379:'Vitality',
};
const TS_SOCIETY: Record<number, string> = { 287:'Celestial Hand',288:'Eldrytch Web',289:'Radiant Blood' };
const TS_MASTERIES: Record<number, string> = { 354:'Melee',355:'Ranged',362:'Summoning' };
const TS_MASTERY_NAMES: Record<number, string> = { 1:'Unarmed',2:'Swords',3:'Axes',4:'Maces',5:'Spears',6:'Daggers',7:'Staves',8:'Bows',9:'Crossbows',10:'Thrown',11:'Two-Handed',12:'Void',13:'War',14:'Life' };
const TS_GENERAL: Record<number, string> = { 181:'Chess Rank',192:'Fishing Skill',199:'Total Augmentations',322:'Aetheria Slots',390:'Enlightenment' };
function societyRank(v: number): string {
if (v >= 1001) return 'Master';
if (v >= 301) return 'Lord';
if (v >= 151) return 'Knight';
if (v >= 31) return 'Adept';
return 'Initiate';
}
const gold = '#af7a30';
const navy = '#000022';
@ -38,10 +70,18 @@ export const CharacterWindow: React.FC<Props> = ({ id, charName, zIndex, vitals
const specSkills = Object.entries(skills).filter(([,v]:any) => v?.training === 'Specialized').sort(([a],[b]) => a.localeCompare(b));
const trainedSkills = Object.entries(skills).filter(([,v]:any) => v?.training === 'Trained').sort(([a],[b]) => a.localeCompare(b));
// Augmentations
// Property-based data
const augs = Object.entries(props).filter(([id,v]) => TS_AUGMENTATIONS[parseInt(id)] && Number(v) > 0).map(([id,v]) => ({ name: TS_AUGMENTATIONS[parseInt(id)], uses: Number(v) }));
const auras = Object.entries(props).filter(([id,v]) => TS_AURAS[parseInt(id)] && Number(v) > 0).map(([id,v]) => ({ name: TS_AURAS[parseInt(id)], uses: Number(v) }));
const ratings = Object.entries(props).filter(([id,v]) => TS_RATINGS[parseInt(id)] && Number(v) > 0).map(([id,v]) => ({ name: TS_RATINGS[parseInt(id)], value: Number(v) }));
const generalRows: Array<{name:string;value:any}> = [];
if (data?.birth) generalRows.push({ name: 'Birth', value: data.birth });
if (data?.deaths != null) generalRows.push({ name: 'Deaths', value: fmt(data.deaths) });
Object.entries(props).forEach(([id,v]) => { const nid = parseInt(id); if (TS_GENERAL[nid]) generalRows.push({ name: TS_GENERAL[nid], value: v }); });
const masteryRows: Array<{name:string;value:string}> = [];
Object.entries(props).forEach(([id,v]) => { const nid = parseInt(id); if (TS_MASTERIES[nid]) masteryRows.push({ name: TS_MASTERIES[nid], value: TS_MASTERY_NAMES[Number(v)] || `Unknown (${v})` }); });
const societyRows: Array<{name:string;rank:string;value:number}> = [];
Object.entries(props).forEach(([id,v]) => { const nid = parseInt(id); if (TS_SOCIETY[nid] && Number(v) > 0) societyRows.push({ name: TS_SOCIETY[nid], rank: societyRank(Number(v)), value: Number(v) }); });
const tabStyle = (active: boolean): React.CSSProperties => ({
padding: '5px 8px', fontSize: 12, fontWeight: 'bold', color: '#fff', cursor: 'pointer', userSelect: 'none',
@ -189,18 +229,28 @@ export const CharacterWindow: React.FC<Props> = ({ id, charName, zIndex, vitals
) : <div style={{ color: '#666', fontStyle: 'italic', textAlign: 'center', padding: 10 }}>No rating data</div>
)}
{rightTab === 2 && (
<div style={{ padding: 6 }}>
{data?.allegiance ? (
<><div style={{ background: '#222', padding: '4px 8px', fontWeight: 'bold', fontSize: 13, borderBottom: `1px solid ${gold}` }}>Allegiance</div>
<div>
{generalRows.length > 0 && (
<><div style={{ background: '#222', padding: '4px 8px', fontWeight: 'bold', fontSize: 13, borderBottom: `1px solid ${gold}` }}>General</div>
<table style={{ width: '100%', fontSize: 13, borderCollapse: 'collapse' }}>
<tbody>
{data.allegiance.name && <tr><td style={{ padding: '2px 6px', color: '#ccc', width: 100 }}>Name</td><td style={{ padding: '2px 6px' }}>{data.allegiance.name}</td></tr>}
{data.allegiance.monarch?.name && <tr><td style={{ padding: '2px 6px', color: '#ccc' }}>Monarch</td><td style={{ padding: '2px 6px' }}>{data.allegiance.monarch.name}</td></tr>}
{data.allegiance.patron?.name && <tr><td style={{ padding: '2px 6px', color: '#ccc' }}>Patron</td><td style={{ padding: '2px 6px' }}>{data.allegiance.patron.name}</td></tr>}
{data.allegiance.rank != null && <tr><td style={{ padding: '2px 6px', color: '#ccc' }}>Rank</td><td style={{ padding: '2px 6px' }}>{data.allegiance.rank}</td></tr>}
</tbody>
<tbody>{generalRows.map(r => <tr key={r.name}><td style={{ padding: '2px 6px' }}>{r.name}</td><td style={{ padding: '2px 6px', textAlign: 'right' }}>{r.value}</td></tr>)}</tbody>
</table></>
) : <div style={{ color: '#666', fontStyle: 'italic', textAlign: 'center', padding: 10 }}>No additional data</div>}
)}
{masteryRows.length > 0 && (
<><div style={{ background: '#222', padding: '4px 8px', fontWeight: 'bold', fontSize: 13, borderBottom: `1px solid ${gold}` }}>Masteries</div>
<table style={{ width: '100%', fontSize: 13, borderCollapse: 'collapse' }}>
<tbody>{masteryRows.map(m => <tr key={m.name}><td style={{ padding: '2px 6px' }}>{m.name}</td><td style={{ padding: '2px 6px', textAlign: 'right' }}>{m.value}</td></tr>)}</tbody>
</table></>
)}
{societyRows.length > 0 && (
<><div style={{ background: '#222', padding: '4px 8px', fontWeight: 'bold', fontSize: 13, borderBottom: `1px solid ${gold}` }}>Society</div>
<table style={{ width: '100%', fontSize: 13, borderCollapse: 'collapse' }}>
<tbody>{societyRows.map(s => <tr key={s.name}><td style={{ padding: '2px 6px' }}>{s.name}</td><td style={{ padding: '2px 6px', textAlign: 'right' }}>{s.rank} ({s.value})</td></tr>)}</tbody>
</table></>
)}
{generalRows.length === 0 && masteryRows.length === 0 && societyRows.length === 0 &&
<div style={{ color: '#666', fontStyle: 'italic', textAlign: 'center', padding: 10 }}>No additional data</div>
}
</div>
)}
</div>