Android build v1.1.5

This commit is contained in:
Warren H
2026-06-30 13:30:33 -04:00
parent 1797154726
commit f6d408f594
21 changed files with 763 additions and 254 deletions
+25 -16
View File
@@ -11,9 +11,11 @@ import { completeRoguelike } from '../profile'
import type { CharacterProfile } from '../profile'
import type { GameMode } from '../gameRepository'
import { PartyMemberFrame } from './PartyFrames'
import { SpellBar, type SpellSlot } from './SpellBars'
import { SpellBar } from './SpellBars'
import { barFillStyle } from './barStyles'
import { focusFirstControl, useGameAction, useInput, type InputAction } from '../input'
import { useDeadlineTimer, useRoundCountdown } from '../hooks/useCountdownTimer'
import { useSpellSlots } from '../hooks/useSpellSlots'
import { useSidedFloatingCombatText } from '../hooks/useFloatingCombatText'
import { usePartyTargeting } from '../hooks/usePartyTargeting'
import { useDualScreen, useDualScreenPublisher } from '../dualScreen'
@@ -31,10 +33,13 @@ import {
spellPowerMultiplier,
spellResourceCost as modifiedSpellResourceCost,
} from '../combat/spellModifiers'
import { advanceCooldowns, regenerateResource, tickSeconds } from '../combat/combatTick'
import { regenerateResource } from '../combat/combatTick'
import { advanceMemberTick } from '../combat/combatEngine'
import { buildStadiumDualScreenState } from '../combat/dualScreenPayloads'
import { applyPvpSpellCast } from '../combat/pvpSpellCasting'
import {
pruneExpiredCooldowns,
} from '../combat/spellCasting'
import {
appendCombatLog,
STADIUM_COMBAT_LOG_LIMIT,
@@ -400,12 +405,16 @@ export function PvpStadiumScreen({
const opponentLabel = liveMatch ? liveMatch.opponentName : `CPU ${cpuDifficulty ?? 1}`
const playerAlive = playerSide.party.some((member) => member.health > 0)
const playerBuffCounts = useMemo(() => createStackCounts(playerSide.buffs), [playerSide.buffs])
const playerSpellSlots = useMemo<SpellSlot[]>(() => starterSpells.map((spell, slotIndex) => ({
...spell,
cost: spellResourceCost(spell, playerBuffCounts, playerSide.freeCastReady),
slotIndex,
remaining: playerSide.cooldowns[spell.id] ?? 0,
})), [playerBuffCounts, playerSide.cooldowns, playerSide.freeCastReady, starterSpells])
const playerSpellSlotCost = useCallback(
(spell: Spell) => spellResourceCost(spell, playerBuffCounts, playerSide.freeCastReady),
[playerBuffCounts, playerSide.freeCastReady],
)
const playerSpellSlots = useSpellSlots({
spells: starterSpells,
cooldowns: playerSide.cooldowns,
active: status === 'playing' && !paused,
cost: playerSpellSlotCost,
})
const opponentBuffSummary = useMemo(
() => summarizeStacks(cpuSide.buffs, buffCatalog),
[buffCatalog, cpuSide.buffs],
@@ -790,7 +799,7 @@ export function PvpStadiumScreen({
...side,
party: nextParty,
resource: regenerateResource(side.resource, RESOURCE_REGEN_PER_TICK, MAX_RESOURCE),
cooldowns: advanceCooldowns(side.cooldowns, tickSeconds(TICK_MS)),
cooldowns: pruneExpiredCooldowns(side.cooldowns),
survivalSeconds: nextSurvival,
dampeningPercent,
}
@@ -1168,16 +1177,16 @@ export function PvpStadiumScreen({
</section>
<section className="dual-top-spell-strip">
{starterSpells.map((spell, slotIndex) => {
const remaining = playerSide.cooldowns[spell.id] ?? 0
const cost = spellResourceCost(spell, playerBuffCounts, playerSide.freeCastReady)
{playerSpellSlots.map((spell, slotIndex) => {
if (!spell) return null
const remaining = spell.remaining
const percent = remaining > 0
? Math.min(100, (remaining / Math.max(1, spell.cooldown)) * 100)
: 0
return (
<button
className="dual-top-spell"
disabled={status !== 'playing' || !playerAlive || remaining > 0 || playerSide.resource < cost || paused}
disabled={status !== 'playing' || !playerAlive || remaining > 0 || playerSide.resource < spell.cost || paused}
key={spell.id}
onClick={() => castPlayerSpell(spell)}
type="button"
@@ -1192,7 +1201,7 @@ export function PvpStadiumScreen({
<div className="dual-top-resource">
<strong>{gameClass.resourceName} {Math.floor(playerSide.resource)} / {MAX_RESOURCE}</strong>
<div className="bar mana-bar">
<span style={{ width: `${(playerSide.resource / MAX_RESOURCE) * 100}%` }} />
<span style={barFillStyle((playerSide.resource / MAX_RESOURCE) * 100)} />
</div>
</div>
</section>
@@ -1226,7 +1235,7 @@ export function PvpStadiumScreen({
</div>
<div className="pvp-resource-wrap">
<span>{gameClass.resourceName} {Math.floor(playerSide.resource)} / {MAX_RESOURCE}</span>
<div className="bar mana-bar"><span style={{ width: `${(playerSide.resource / MAX_RESOURCE) * 100}%` }} /></div>
<div className="bar mana-bar"><span style={barFillStyle((playerSide.resource / MAX_RESOURCE) * 100)} /></div>
</div>
</div>
<div className="party-grid pvp-party-grid">
@@ -1256,7 +1265,7 @@ export function PvpStadiumScreen({
</div>
<div className="pvp-resource-wrap">
<span>{gameClass.resourceName} {Math.floor(cpuSide.resource)} / {MAX_RESOURCE}</span>
<div className="bar mana-bar"><span style={{ width: `${(cpuSide.resource / MAX_RESOURCE) * 100}%` }} /></div>
<div className="bar mana-bar"><span style={barFillStyle((cpuSide.resource / MAX_RESOURCE) * 100)} /></div>
</div>
</div>
<div className="party-grid pvp-party-grid">