Android build v1.1.12
This commit is contained in:
@@ -152,6 +152,14 @@ type LivePvpMatch = {
|
||||
opponentClassName: string
|
||||
}
|
||||
|
||||
type PvpOverlayNavEntry =
|
||||
| { kind: 'queueBack'; row: number; column: number }
|
||||
| { kind: 'pauseResume'; row: number; column: number }
|
||||
| { kind: 'pauseLeave'; row: number; column: number }
|
||||
| { kind: 'upgradeBuff'; index: number; row: number; column: number }
|
||||
| { kind: 'upgradeDebuff'; index: number; row: number; column: number }
|
||||
| { kind: 'upgradeContinue'; row: number; column: number; disabled?: boolean }
|
||||
|
||||
const REVIVE_PARTY_CHOICE: Choice<SelfBuffId> = {
|
||||
id: 'revive-party-members',
|
||||
name: 'Revive Party Members',
|
||||
@@ -356,6 +364,7 @@ export function PvPRoguelikeScreen({
|
||||
const [playerDebuffChoices, setPlayerDebuffChoices] = useState<Array<Choice<OpponentDebuffId>>>([])
|
||||
const [selectedBuff, setSelectedBuff] = useState<Choice<SelfBuffId> | null>(null)
|
||||
const [selectedDebuff, setSelectedDebuff] = useState<Choice<OpponentDebuffId> | null>(null)
|
||||
const [overlaySelectedIndex, setOverlaySelectedIndex] = useState(0)
|
||||
const [encountersCleared, setEncountersCleared] = useState(0)
|
||||
const [paused, setPaused] = useState(false)
|
||||
const [targetGroup, setTargetGroup] = useState<0 | 1 | 2>(0)
|
||||
@@ -695,6 +704,7 @@ export function PvPRoguelikeScreen({
|
||||
setStartStage(setup.startStage)
|
||||
setStage(setup.startStage)
|
||||
setStatus('queueing')
|
||||
setOverlaySelectedIndex(0)
|
||||
setPlayerSide(setup.playerSide)
|
||||
setCpuSide(setup.opponentSide)
|
||||
setSelectedTargetId(partyTemplate[0].id)
|
||||
@@ -1025,6 +1035,7 @@ export function PvPRoguelikeScreen({
|
||||
setPlayerDebuffChoices(chooseRandom(opponentDebuffChoicesCatalog, 3))
|
||||
setSelectedBuff(null)
|
||||
setSelectedDebuff(null)
|
||||
setOverlaySelectedIndex(0)
|
||||
setStatus('upgrade-choice')
|
||||
}, [opponentDebuffChoicesCatalog, selfBuffChoicesCatalog, startUpgradeTimer])
|
||||
|
||||
@@ -1312,13 +1323,140 @@ export function PvPRoguelikeScreen({
|
||||
addLog(`You chose ${chosenBuff.name} and ${chosenDebuff.name}. CPU ${cpuDifficulty} chose ${cpuBuff.name} and ${cpuDebuff.name}.`, 'system')
|
||||
}, [addLog, beginRoundCountdown, contentType, cpuDifficulty, encounter, encounterIndex, encounterPool, encounters, finishRoguelikeRun, liveMatch, maxResource, opponentDebuffChoicesCatalog, selectedBuff, selectedDebuff, selfBuffChoicesCatalog, stage, starterSpells])
|
||||
|
||||
function pvpOverlayEntries(): PvpOverlayNavEntry[] {
|
||||
if (status === 'queueing') return [{ kind: 'queueBack', row: 0, column: 0 }]
|
||||
if (paused) {
|
||||
return [
|
||||
{ kind: 'pauseResume', row: 0, column: 0 },
|
||||
{ kind: 'pauseLeave', row: 1, column: 0 },
|
||||
]
|
||||
}
|
||||
if (status !== 'upgrade-choice') return []
|
||||
const entries: PvpOverlayNavEntry[] = [
|
||||
...playerBuffChoices.map((_, index) => ({
|
||||
kind: 'upgradeBuff' as const,
|
||||
index,
|
||||
row: index,
|
||||
column: 0,
|
||||
})),
|
||||
...playerDebuffChoices.map((_, index) => ({
|
||||
kind: 'upgradeDebuff' as const,
|
||||
index,
|
||||
row: index,
|
||||
column: 1,
|
||||
})),
|
||||
]
|
||||
entries.push({
|
||||
kind: 'upgradeContinue',
|
||||
row: Math.max(playerBuffChoices.length, playerDebuffChoices.length),
|
||||
column: 1,
|
||||
disabled: !selectedBuff || !selectedDebuff || liveUpgradePending,
|
||||
})
|
||||
return entries
|
||||
}
|
||||
|
||||
function pvpOverlayEntryDisabled(entry: PvpOverlayNavEntry) {
|
||||
return entry.kind === 'upgradeContinue' && Boolean(entry.disabled)
|
||||
}
|
||||
|
||||
function activePvpOverlayEntry(entries = pvpOverlayEntries()) {
|
||||
const bounded = Math.min(overlaySelectedIndex, entries.length - 1)
|
||||
const active = entries[bounded]
|
||||
if (active && !pvpOverlayEntryDisabled(active)) return active
|
||||
return entries.find((entry) => !pvpOverlayEntryDisabled(entry))
|
||||
}
|
||||
|
||||
function pvpOverlayEntrySelected(kind: PvpOverlayNavEntry['kind'], index?: number) {
|
||||
const active = activePvpOverlayEntry()
|
||||
if (!active || active.kind !== kind) return false
|
||||
if ('index' in active || index !== undefined) return 'index' in active && active.index === index
|
||||
return true
|
||||
}
|
||||
|
||||
function setPvpOverlayCursor(kind: PvpOverlayNavEntry['kind'], index?: number) {
|
||||
const entries = pvpOverlayEntries()
|
||||
const nextIndex = entries.findIndex((entry) => {
|
||||
if (entry.kind !== kind) return false
|
||||
if ('index' in entry || index !== undefined) return 'index' in entry && entry.index === index
|
||||
return true
|
||||
})
|
||||
if (nextIndex >= 0) setOverlaySelectedIndex(nextIndex)
|
||||
}
|
||||
|
||||
function movePvpOverlaySelection(action: string) {
|
||||
const entries = pvpOverlayEntries()
|
||||
const enabledEntries = entries
|
||||
.map((entry, index) => ({ entry, index }))
|
||||
.filter(({ entry }) => !pvpOverlayEntryDisabled(entry))
|
||||
if (enabledEntries.length === 0) return
|
||||
setOverlaySelectedIndex((current) => {
|
||||
const candidate = entries[Math.min(current, entries.length - 1)]
|
||||
const active = candidate && !pvpOverlayEntryDisabled(candidate)
|
||||
? candidate
|
||||
: enabledEntries[0]?.entry
|
||||
if (!active) return current
|
||||
const candidates = enabledEntries.filter(({ entry }) => {
|
||||
if (entry === active) return false
|
||||
if (action === 'navigateLeft') return entry.row === active.row && entry.column < active.column
|
||||
if (action === 'navigateRight') return entry.row === active.row && entry.column > active.column
|
||||
if (action === 'navigateUp') return entry.row < active.row
|
||||
return entry.row > active.row
|
||||
})
|
||||
if (candidates.length === 0) return entries.findIndex((entry) => entry === active)
|
||||
candidates.sort((a, b) => {
|
||||
const aPrimary = Math.abs(a.entry.row - active.row) + Math.abs(a.entry.column - active.column)
|
||||
const bPrimary = Math.abs(b.entry.row - active.row) + Math.abs(b.entry.column - active.column)
|
||||
return aPrimary - bPrimary || a.index - b.index
|
||||
})
|
||||
return candidates[0]?.index ?? current
|
||||
})
|
||||
}
|
||||
|
||||
function openPvpOverlayEntry(entry: PvpOverlayNavEntry | undefined) {
|
||||
if (!entry || pvpOverlayEntryDisabled(entry)) return
|
||||
if (entry.kind === 'queueBack') onExit()
|
||||
else if (entry.kind === 'pauseResume') setPaused(false)
|
||||
else if (entry.kind === 'pauseLeave') onExit()
|
||||
else if (entry.kind === 'upgradeBuff') setSelectedBuff(playerBuffChoices[entry.index] ?? null)
|
||||
else if (entry.kind === 'upgradeDebuff') setSelectedDebuff(playerDebuffChoices[entry.index] ?? null)
|
||||
else if (entry.kind === 'upgradeContinue') confirmUpgradeChoices()
|
||||
}
|
||||
|
||||
useGameAction((action) => {
|
||||
if (status === 'queueing' || status === 'round-countdown') {
|
||||
if (action === 'back' || action === 'pause') onExit()
|
||||
if (status === 'queueing' && action === 'confirm') openPvpOverlayEntry(activePvpOverlayEntry())
|
||||
return
|
||||
}
|
||||
if (paused) {
|
||||
if (action === 'back' || action === 'pause') {
|
||||
setPaused(false)
|
||||
return
|
||||
}
|
||||
if (action === 'confirm') {
|
||||
openPvpOverlayEntry(activePvpOverlayEntry())
|
||||
return
|
||||
}
|
||||
if (action.startsWith('navigate')) movePvpOverlaySelection(action)
|
||||
return
|
||||
}
|
||||
if (status === 'upgrade-choice') {
|
||||
if (action === 'confirm') {
|
||||
openPvpOverlayEntry(activePvpOverlayEntry())
|
||||
return
|
||||
}
|
||||
if (action.startsWith('navigate')) movePvpOverlaySelection(action)
|
||||
return
|
||||
}
|
||||
if (action === 'toggleSpeed') {
|
||||
if (status === 'playing') setSpeedMultiplier((value) => (value === 1 ? 2 : 1))
|
||||
return
|
||||
}
|
||||
if (action === 'pause' || action === 'back') {
|
||||
if (status === 'playing') setPaused((value) => !value)
|
||||
if (status === 'playing') {
|
||||
setOverlaySelectedIndex(0)
|
||||
setPaused((value) => !value)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (paused || status !== 'playing') return
|
||||
@@ -1434,9 +1572,18 @@ export function PvPRoguelikeScreen({
|
||||
>
|
||||
<section className="content-screen pvp-match-screen">
|
||||
{status === 'queueing' && (
|
||||
<div className="placeholder-panel">
|
||||
<div className="placeholder-panel pvp-match-queue-panel" data-game-nav-active="true">
|
||||
<div className="placeholder-runes">P V P</div>
|
||||
<p>{queueMessage}</p>
|
||||
<button
|
||||
className={`secondary-result-button ${pvpOverlayEntrySelected('queueBack') ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
onClick={onExit}
|
||||
onPointerDown={() => setPvpOverlayCursor('queueBack')}
|
||||
type="button"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1552,7 +1699,7 @@ export function PvPRoguelikeScreen({
|
||||
)}
|
||||
|
||||
{status === 'upgrade-choice' && (
|
||||
<div className="result-screen">
|
||||
<div className="result-screen" data-game-nav-active="true">
|
||||
<div className="pvp-upgrade-dialog">
|
||||
<div className="pvp-upgrade-header">
|
||||
<div>
|
||||
@@ -1567,9 +1714,11 @@ export function PvPRoguelikeScreen({
|
||||
<div className="upgrade-choice-grid">
|
||||
{playerBuffChoices.map((choice) => (
|
||||
<button
|
||||
className={selectedBuff?.id === choice.id ? 'selected-upgrade' : ''}
|
||||
className={`${selectedBuff?.id === choice.id ? 'selected-upgrade' : ''} ${pvpOverlayEntrySelected('upgradeBuff', playerBuffChoices.indexOf(choice)) ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
key={choice.id}
|
||||
onClick={() => setSelectedBuff(choice)}
|
||||
onPointerDown={() => setPvpOverlayCursor('upgradeBuff', playerBuffChoices.indexOf(choice))}
|
||||
type="button"
|
||||
>
|
||||
<strong>{choice.name}</strong>
|
||||
@@ -1583,9 +1732,11 @@ export function PvPRoguelikeScreen({
|
||||
<div className="upgrade-choice-grid">
|
||||
{playerDebuffChoices.map((choice) => (
|
||||
<button
|
||||
className={selectedDebuff?.id === choice.id ? 'selected-upgrade' : ''}
|
||||
className={`${selectedDebuff?.id === choice.id ? 'selected-upgrade' : ''} ${pvpOverlayEntrySelected('upgradeDebuff', playerDebuffChoices.indexOf(choice)) ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
key={choice.id}
|
||||
onClick={() => setSelectedDebuff(choice)}
|
||||
onPointerDown={() => setPvpOverlayCursor('upgradeDebuff', playerDebuffChoices.indexOf(choice))}
|
||||
type="button"
|
||||
>
|
||||
<strong>{choice.name}</strong>
|
||||
@@ -1596,7 +1747,14 @@ export function PvPRoguelikeScreen({
|
||||
</div>
|
||||
</div>
|
||||
{liveUpgradePending && <p>Waiting for opponent choice...</p>}
|
||||
<button className="secondary-result-button" disabled={!selectedBuff || !selectedDebuff || liveUpgradePending} onClick={() => confirmUpgradeChoices()} type="button">
|
||||
<button
|
||||
className={`secondary-result-button ${pvpOverlayEntrySelected('upgradeContinue') ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
disabled={!selectedBuff || !selectedDebuff || liveUpgradePending}
|
||||
onClick={() => confirmUpgradeChoices()}
|
||||
onPointerDown={() => setPvpOverlayCursor('upgradeContinue')}
|
||||
type="button"
|
||||
>
|
||||
{liveUpgradePending ? 'Waiting' : 'Continue'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -1604,12 +1762,28 @@ export function PvPRoguelikeScreen({
|
||||
)}
|
||||
|
||||
{paused && (
|
||||
<div className="pause-screen">
|
||||
<div className="pause-screen" data-game-nav-active="true">
|
||||
<div>
|
||||
<p className="eyebrow">Paused</p>
|
||||
<h2>{contentType === 'raid' ? 'Raid Clash' : 'Dungeon Clash'}</h2>
|
||||
<button onClick={() => setPaused(false)} type="button">Resume</button>
|
||||
<button className="secondary-result-button" onClick={onExit} type="button">Leave</button>
|
||||
<button
|
||||
className={pvpOverlayEntrySelected('pauseResume') ? 'game-selected' : ''}
|
||||
data-controller-nav="skip"
|
||||
onClick={() => setPaused(false)}
|
||||
onPointerDown={() => setPvpOverlayCursor('pauseResume')}
|
||||
type="button"
|
||||
>
|
||||
Resume
|
||||
</button>
|
||||
<button
|
||||
className={`secondary-result-button ${pvpOverlayEntrySelected('pauseLeave') ? 'game-selected' : ''}`}
|
||||
data-controller-nav="skip"
|
||||
onClick={onExit}
|
||||
onPointerDown={() => setPvpOverlayCursor('pauseLeave')}
|
||||
type="button"
|
||||
>
|
||||
Leave
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user