Android build v1.0.25

This commit is contained in:
Warren H
2026-06-18 23:28:43 -04:00
parent 7fe62d8c82
commit 814eb1998d
4 changed files with 42 additions and 25 deletions
Binary file not shown.
+2 -2
View File
@@ -7,8 +7,8 @@ android {
applicationId "com.warren.iwanttoheal" applicationId "com.warren.iwanttoheal"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 41 versionCode 42
versionName "1.0.24" versionName "1.0.25"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions { aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+10
View File
@@ -131,6 +131,13 @@ function App() {
}) })
}, [screen]) }, [screen])
useEffect(() => {
if (!authChecked || !account || !profile || screen === 'combat') return
window.requestAnimationFrame(() => {
focusFirstControl()
})
}, [account, authChecked, profile, screen])
useEffect(() => { useEffect(() => {
window.localStorage.setItem(LAST_DIFFICULTY_KEY, String(selectedDifficultyId)) window.localStorage.setItem(LAST_DIFFICULTY_KEY, String(selectedDifficultyId))
}, [selectedDifficultyId]) }, [selectedDifficultyId])
@@ -148,6 +155,9 @@ function App() {
setScreen('menu') setScreen('menu')
setError('') setError('')
setServerMessage('') setServerMessage('')
window.requestAnimationFrame(() => {
focusFirstControl()
})
} }
async function signOut() { async function signOut() {
+30 -23
View File
@@ -374,6 +374,7 @@ export function CombatScreen({
const partyRef = useRef(partyTemplate) const partyRef = useRef(partyTemplate)
const enemyHealthRef = useRef(encounters[initialEncounterIndex].maxHealth) const enemyHealthRef = useRef(encounters[initialEncounterIndex].maxHealth)
const elapsedTicksRef = useRef(0) const elapsedTicksRef = useRef(0)
const selectedIdRef = useRef(partyTemplate[0].id)
const encounter = encounters[encounterIndex] const encounter = encounters[encounterIndex]
const currentPart = getCurrentPart(encounterIndex) const currentPart = getCurrentPart(encounterIndex)
const firstEncounterIndex = (startPart - 1) * 3 const firstEncounterIndex = (startPart - 1) * 3
@@ -415,6 +416,11 @@ export function CombatScreen({
}) })
}, [paused]) }, [paused])
const setSelectedTargetId = useCallback((id: string) => {
selectedIdRef.current = id
setSelectedId(id)
}, [])
const addLog = useCallback((text: string, tone: CombatLogEntry['tone']) => { const addLog = useCallback((text: string, tone: CombatLogEntry['tone']) => {
const entry = { id: nextLogId.current++, text, tone } const entry = { id: nextLogId.current++, text, tone }
setLog((current) => [entry, ...current].slice(0, 60)) setLog((current) => [entry, ...current].slice(0, 60))
@@ -467,7 +473,7 @@ export function CombatScreen({
if (roguelikeMode) setRoguelikeEncounters(nextRoguelikeEncounters) if (roguelikeMode) setRoguelikeEncounters(nextRoguelikeEncounters)
setRoguelikeStage(1) setRoguelikeStage(1)
setParty(freshParty) setParty(freshParty)
setSelectedId(partyTemplate[0].id) setSelectedTargetId(partyTemplate[0].id)
setResource(maxResource) setResource(maxResource)
setEncounterIndex(initialEncounterIndex) setEncounterIndex(initialEncounterIndex)
setEnemyHealth(nextEncounters[initialEncounterIndex].maxHealth) setEnemyHealth(nextEncounters[initialEncounterIndex].maxHealth)
@@ -494,7 +500,7 @@ export function CombatScreen({
runStartedAtRef.current = Date.now() runStartedAtRef.current = Date.now()
partStartTimesRef.current = { [startPart]: runStartedAtRef.current } partStartTimesRef.current = { [startPart]: runStartedAtRef.current }
setLog([{ id: nextLogId.current++, text: 'A new run begins.', tone: 'system' }]) setLog([{ id: nextLogId.current++, text: 'A new run begins.', tone: 'system' }])
}, [difficulty, initialEncounterIndex, maxResource, partyTemplate, roguelikeMode, roguelikePool, startPart, staticEncounters]) }, [difficulty, initialEncounterIndex, maxResource, partyTemplate, roguelikeMode, roguelikePool, setSelectedTargetId, startPart, staticEncounters])
const castSpell = useCallback( const castSpell = useCallback(
(spell: Spell) => { (spell: Spell) => {
@@ -502,26 +508,27 @@ export function CombatScreen({
if (status !== 'playing' || cooldowns[spell.id] > 0 || resource < effectiveCost) return if (status !== 'playing' || cooldowns[spell.id] > 0 || resource < effectiveCost) return
const healer = partyRef.current.find((member) => member.id === 'mira') const healer = partyRef.current.find((member) => member.id === 'mira')
if (!healer || healer.health <= 0) return if (!healer || healer.health <= 0) return
const selected = partyRef.current.find((member) => member.id === selectedId) const targetId = selectedIdRef.current
const selected = partyRef.current.find((member) => member.id === targetId)
if (!selected || selected.health <= 0) return if (!selected || selected.health <= 0) return
const extraTarget = (blockedIds: string[]) => partyRef.current const extraTarget = (blockedIds: string[]) => partyRef.current
.filter((member) => member.health > 0 && !blockedIds.includes(member.id)) .filter((member) => member.health > 0 && !blockedIds.includes(member.id))
.sort((left, right) => (left.health / left.maxHealth) - (right.health / right.maxHealth))[0] .sort((left, right) => (left.health / left.maxHealth) - (right.health / right.maxHealth))[0]
const directTargets = new Set([selectedId]) const directTargets = new Set([targetId])
const hotTargets = new Set<string>() const hotTargets = new Set<string>()
const shieldTargets = new Set<string>() const shieldTargets = new Set<string>()
if (spell.kind === 'hot') hotTargets.add(selectedId) if (spell.kind === 'hot') hotTargets.add(targetId)
if (spell.kind === 'shield') shieldTargets.add(selectedId) if (spell.kind === 'shield') shieldTargets.add(targetId)
if (spell.name === 'Mend' && activeSetEffects.has('mend_extra_target')) { if (spell.name === 'Mend' && activeSetEffects.has('mend_extra_target')) {
const extra = extraTarget([selectedId]) const extra = extraTarget([targetId])
if (extra) directTargets.add(extra.id) if (extra) directTargets.add(extra.id)
} }
if (spell.name === 'Renew' && activeSetEffects.has('renew_extra_target')) { if (spell.name === 'Renew' && activeSetEffects.has('renew_extra_target')) {
const extra = extraTarget([selectedId]) const extra = extraTarget([targetId])
if (extra) hotTargets.add(extra.id) if (extra) hotTargets.add(extra.id)
} }
if (spell.name === 'Mend' && activeSetEffects.has('mend_applies_renew')) { if (spell.name === 'Mend' && activeSetEffects.has('mend_applies_renew')) {
hotTargets.add(selectedId) hotTargets.add(targetId)
} }
const extraTargets = upgradeStackCount(roguelikeUpgrades, `slot${spell.key as SlotKey}-extra-target` as RoguelikeUpgradeId) const extraTargets = upgradeStackCount(roguelikeUpgrades, `slot${spell.key as SlotKey}-extra-target` as RoguelikeUpgradeId)
for (let index = 0; index < extraTargets; index += 1) { for (let index = 0; index < extraTargets; index += 1) {
@@ -599,7 +606,7 @@ export function CombatScreen({
setParty(nextParty) setParty(nextParty)
addLog(`${spell.name} cast on ${spell.kind === 'group' ? 'the party' : selected.name}${effectiveCost === 0 ? ' for free' : ''}.`, 'heal') addLog(`${spell.name} cast on ${spell.kind === 'group' ? 'the party' : selected.name}${effectiveCost === 0 ? ' for free' : ''}.`, 'heal')
}, },
[activeSetEffects, addFloatingHeal, addLog, cooldowns, freeCastReady, resource, roguelikeUpgrades, selectedId, status], [activeSetEffects, addFloatingHeal, addLog, cooldowns, freeCastReady, resource, roguelikeUpgrades, status],
) )
const finishRun = useCallback( const finishRun = useCallback(
@@ -664,18 +671,18 @@ export function CombatScreen({
const selectRelativeTarget = useCallback((direction: -1 | 1) => { const selectRelativeTarget = useCallback((direction: -1 | 1) => {
const living = partyRef.current.filter((member) => member.health > 0) const living = partyRef.current.filter((member) => member.health > 0)
if (living.length === 0) return if (living.length === 0) return
const currentIndex = living.findIndex((member) => member.id === selectedId) const currentIndex = living.findIndex((member) => member.id === selectedIdRef.current)
const nextIndex = currentIndex < 0 const nextIndex = currentIndex < 0
? 0 ? 0
: (currentIndex + direction + living.length) % living.length : (currentIndex + direction + living.length) % living.length
setSelectedId(living[nextIndex].id) setSelectedTargetId(living[nextIndex].id)
}, [selectedId]) }, [setSelectedTargetId])
const selectDirectionalTarget = useCallback((action: InputAction) => { const selectDirectionalTarget = useCallback((action: InputAction) => {
const columns = dungeon.partySize >= 10 ? 6 : 3 const columns = dungeon.partySize >= 10 ? 6 : 3
const currentIndex = partyRef.current.findIndex((member) => member.id === selectedId) const currentIndex = partyRef.current.findIndex((member) => member.id === selectedIdRef.current)
if (currentIndex < 0) { if (currentIndex < 0) {
setSelectedId(partyRef.current[0].id) setSelectedTargetId(partyRef.current[0].id)
return return
} }
const currentRow = Math.floor(currentIndex / columns) const currentRow = Math.floor(currentIndex / columns)
@@ -709,14 +716,14 @@ export function CombatScreen({
: Math.abs(b.column - currentColumn) : Math.abs(b.column - currentColumn)
return aPrimary - bPrimary || aSecondary - bSecondary return aPrimary - bPrimary || aSecondary - bSecondary
}) })
if (candidates[0]) setSelectedId(candidates[0].member.id) if (candidates[0]) setSelectedTargetId(candidates[0].member.id)
}, [dungeon.partySize, selectedId]) }, [dungeon.partySize, setSelectedTargetId])
const selectDirectTarget = useCallback((slot: number) => { const selectDirectTarget = useCallback((slot: number) => {
const index = slot + (dungeon.partySize > 6 ? targetGroup * 6 : 0) const index = slot + (dungeon.partySize > 6 ? targetGroup * 6 : 0)
const member = partyRef.current[index] const member = partyRef.current[index]
if (member) setSelectedId(member.id) if (member) setSelectedTargetId(member.id)
}, [dungeon.partySize, targetGroup]) }, [dungeon.partySize, setSelectedTargetId, targetGroup])
const chooseRoguelikeUpgrade = useCallback((upgrade: RoguelikeUpgrade) => { const chooseRoguelikeUpgrade = useCallback((upgrade: RoguelikeUpgrade) => {
if (!roguelikeMode) return if (!roguelikeMode) return
@@ -778,9 +785,9 @@ export function CombatScreen({
setTargetGroup((current) => { setTargetGroup((current) => {
const groupCount = Math.max(1, Math.ceil(partyRef.current.length / 6)) const groupCount = Math.max(1, Math.ceil(partyRef.current.length / 6))
const next = ((current + 1) % groupCount) as 0 | 1 | 2 const next = ((current + 1) % groupCount) as 0 | 1 | 2
const selectedIndex = partyRef.current.findIndex((member) => member.id === selectedId) const selectedIndex = partyRef.current.findIndex((member) => member.id === selectedIdRef.current)
const nextMember = partyRef.current[(selectedIndex < 0 ? 0 : selectedIndex % 6) + next * 6] const nextMember = partyRef.current[(selectedIndex < 0 ? 0 : selectedIndex % 6) + next * 6]
if (nextMember) setSelectedId(nextMember.id) if (nextMember) setSelectedTargetId(nextMember.id)
return next return next
}) })
return return
@@ -1134,7 +1141,7 @@ export function CombatScreen({
<button <button
className={`party-member ${selectedId === member.id ? 'selected' : ''} ${member.health <= 0 ? 'dead' : ''}`} className={`party-member ${selectedId === member.id ? 'selected' : ''} ${member.health <= 0 ? 'dead' : ''}`}
key={member.id} key={member.id}
onClick={() => setSelectedId(member.id)} onClick={() => setSelectedTargetId(member.id)}
aria-pressed={selectedId === member.id} aria-pressed={selectedId === member.id}
type="button" type="button"
> >
@@ -1219,7 +1226,7 @@ export function CombatScreen({
{dualScreenEnabled && ( {dualScreenEnabled && (
<DualScreenTopCombat <DualScreenTopCombat
state={dualScreenState} state={dualScreenState}
onSelectTarget={setSelectedId} onSelectTarget={setSelectedTargetId}
/> />
)} )}