Android build v1.1.16
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { asIwt2HealerId, type Iwt2HealerId } from '../content/healerAbilities'
|
||||
|
||||
export type Iwt2InventoryItem = {
|
||||
id: string
|
||||
name: string
|
||||
@@ -5,21 +7,35 @@ export type Iwt2InventoryItem = {
|
||||
rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary'
|
||||
}
|
||||
|
||||
export type Iwt2ArmorPaletteId = 'guild_green' | 'sun_gold' | 'ember_red' | 'moon_blue'
|
||||
|
||||
export type Iwt2CollectionLog = {
|
||||
bossKills: Record<string, number>
|
||||
dropsFound: Record<string, number>
|
||||
}
|
||||
|
||||
export type Iwt2Character = {
|
||||
name: string
|
||||
level: number
|
||||
experience: number
|
||||
healerStyle: Iwt2HealerId
|
||||
armorPalette: Iwt2ArmorPaletteId
|
||||
}
|
||||
|
||||
export type Iwt2CloudSlot = {
|
||||
savedAt: number
|
||||
character: Iwt2Character
|
||||
inventory: Iwt2InventoryItem[]
|
||||
collectionLog: Iwt2CollectionLog
|
||||
}
|
||||
|
||||
export type Iwt2Save = {
|
||||
version: 1
|
||||
updatedAt: number
|
||||
character: {
|
||||
name: string
|
||||
level: number
|
||||
experience: number
|
||||
}
|
||||
character: Iwt2Character
|
||||
inventory: Iwt2InventoryItem[]
|
||||
collectionLog: Iwt2CollectionLog
|
||||
cloudSlot?: Iwt2CloudSlot
|
||||
}
|
||||
|
||||
const IWT2_SAVE_KEY = 'i-want-to-heal-2:save:v1'
|
||||
@@ -32,6 +48,8 @@ export function createDefaultIwt2Save(): Iwt2Save {
|
||||
name: 'Healer',
|
||||
level: 1,
|
||||
experience: 0,
|
||||
healerStyle: 'dawnweaver',
|
||||
armorPalette: 'guild_green',
|
||||
},
|
||||
inventory: [],
|
||||
collectionLog: {
|
||||
@@ -52,12 +70,15 @@ function normalizeSave(value: unknown): Iwt2Save {
|
||||
name: candidate.character?.name || 'Healer',
|
||||
level: Math.max(1, Math.floor(candidate.character?.level ?? 1)),
|
||||
experience: Math.max(0, Math.floor(candidate.character?.experience ?? 0)),
|
||||
healerStyle: asIwt2HealerId(candidate.character?.healerStyle),
|
||||
armorPalette: asIwt2ArmorPaletteId(candidate.character?.armorPalette),
|
||||
},
|
||||
inventory: Array.isArray(candidate.inventory) ? candidate.inventory : [],
|
||||
collectionLog: {
|
||||
bossKills: candidate.collectionLog?.bossKills ?? {},
|
||||
dropsFound: candidate.collectionLog?.dropsFound ?? {},
|
||||
},
|
||||
cloudSlot: normalizeCloudSlot(candidate.cloudSlot),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +130,91 @@ export function recordIwt2BossKill(save: Iwt2Save, bossId: string): Iwt2Save {
|
||||
}
|
||||
}
|
||||
|
||||
export function updateIwt2CharacterSettings(
|
||||
save: Iwt2Save,
|
||||
settings: Partial<Pick<Iwt2Save['character'], 'name' | 'healerStyle' | 'armorPalette'>>,
|
||||
): Iwt2Save {
|
||||
return {
|
||||
...save,
|
||||
updatedAt: Date.now(),
|
||||
character: {
|
||||
...save.character,
|
||||
...settings,
|
||||
name: normalizeCharacterName(settings.name ?? save.character.name),
|
||||
healerStyle: asIwt2HealerId(settings.healerStyle ?? save.character.healerStyle),
|
||||
armorPalette: asIwt2ArmorPaletteId(settings.armorPalette ?? save.character.armorPalette),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function snapshotIwt2CloudSlot(save: Iwt2Save): Iwt2Save {
|
||||
return {
|
||||
...save,
|
||||
updatedAt: Date.now(),
|
||||
cloudSlot: {
|
||||
savedAt: Date.now(),
|
||||
character: { ...save.character },
|
||||
inventory: save.inventory.map((item) => ({ ...item })),
|
||||
collectionLog: {
|
||||
bossKills: { ...save.collectionLog.bossKills },
|
||||
dropsFound: { ...save.collectionLog.dropsFound },
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function restoreIwt2CloudSlot(save: Iwt2Save): Iwt2Save {
|
||||
if (!save.cloudSlot) return save
|
||||
return {
|
||||
...save,
|
||||
updatedAt: Date.now(),
|
||||
character: { ...save.cloudSlot.character },
|
||||
inventory: save.cloudSlot.inventory.map((item) => ({ ...item })),
|
||||
collectionLog: {
|
||||
bossKills: { ...save.cloudSlot.collectionLog.bossKills },
|
||||
dropsFound: { ...save.cloudSlot.collectionLog.dropsFound },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function bossDropFor(bossId: string): { id: string, name: string } {
|
||||
if (bossId === 'yian-kut-ku') return { id: 'yian-kut-ku-scale', name: 'Yian Kut Ku Scale' }
|
||||
if (bossId === 'great-jaggi') return { id: 'great-jaggi-hide', name: 'Great Jaggi Hide' }
|
||||
if (bossId === 'khezu') return { id: 'khezu-pearl', name: 'Khezu Pearl' }
|
||||
return { id: 'raw-bulldrome-coin', name: 'Raw Bulldrome Coin' }
|
||||
}
|
||||
|
||||
function asIwt2ArmorPaletteId(value: unknown): Iwt2ArmorPaletteId {
|
||||
return value === 'sun_gold'
|
||||
|| value === 'ember_red'
|
||||
|| value === 'moon_blue'
|
||||
|| value === 'guild_green'
|
||||
? value
|
||||
: 'guild_green'
|
||||
}
|
||||
|
||||
function normalizeCharacterName(name: string): string {
|
||||
const trimmed = name.trim().slice(0, 18)
|
||||
return trimmed || 'Healer'
|
||||
}
|
||||
|
||||
function normalizeCloudSlot(value: unknown): Iwt2CloudSlot | undefined {
|
||||
if (!value || typeof value !== 'object') return undefined
|
||||
const candidate = value as Partial<Iwt2CloudSlot>
|
||||
if (!candidate.character || !candidate.collectionLog) return undefined
|
||||
return {
|
||||
savedAt: typeof candidate.savedAt === 'number' ? candidate.savedAt : Date.now(),
|
||||
character: {
|
||||
name: normalizeCharacterName(candidate.character.name ?? 'Healer'),
|
||||
level: Math.max(1, Math.floor(candidate.character.level ?? 1)),
|
||||
experience: Math.max(0, Math.floor(candidate.character.experience ?? 0)),
|
||||
healerStyle: asIwt2HealerId(candidate.character.healerStyle),
|
||||
armorPalette: asIwt2ArmorPaletteId(candidate.character.armorPalette),
|
||||
},
|
||||
inventory: Array.isArray(candidate.inventory) ? candidate.inventory : [],
|
||||
collectionLog: {
|
||||
bossKills: candidate.collectionLog.bossKills ?? {},
|
||||
dropsFound: candidate.collectionLog.dropsFound ?? {},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user