feat: Hinweis und hervorgehobener End-game-Knopf, wenn kein Zug mehr Gold bringt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
426365f502
commit
50d4394364
4 changed files with 45 additions and 1 deletions
3
PLAN.md
3
PLAN.md
|
|
@ -197,3 +197,6 @@ Abgabe: **9. Dezember 2026, 03:00 MEZ**. Eingereicht wird in „Best Daily Game
|
|||
„All 3 stars! Keep going for more gold – or end the game.“
|
||||
- Erreichte Ziele werden **golden** hervorgehoben (wie `goal-chip.done` im Hauptspiel).
|
||||
- `devvit playtest` trägt `dev.subreddit` (`ninelands_game_dev`) in `devvit.json` ein.
|
||||
- Rückmeldung Besitzer: Bei „One farm per land“ bleiben am Ende oft nur Ritter, die Gold kosten. Darum prüft der
|
||||
Client nach jedem Zug, ob noch ein Zug Gold bringt (`gainLeft`, alle gültigen Züge per `preview`, < 1 ms). Wenn
|
||||
nicht: Hinweis „No move left gains gold – end the game to keep what you have.“ und „End game“ leuchtet golden.
|
||||
|
|
|
|||
|
|
@ -181,6 +181,23 @@ button.end {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button.end.suggest {
|
||||
background: var(--px-gold);
|
||||
animation: pulse 1.2s steps(2) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
50% {
|
||||
outline: 2px solid var(--px-parchment);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
button.end.suggest {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
button.end.armed {
|
||||
background: var(--px-red);
|
||||
color: var(--px-parchment);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,11 @@ function update(): void {
|
|||
bothGoal.classList.toggle('done', stars.both)
|
||||
undoBtn.disabled = finished || !game.canUndo
|
||||
endBtn.disabled = finished || game.moves.length === 0
|
||||
gainCache = null
|
||||
endBtn.classList.toggle(
|
||||
'suggest',
|
||||
!finished && game.moves.length > 0 && !gainLeft(),
|
||||
)
|
||||
const hasCastle = game.count('HIVEMOTHER') > 0
|
||||
for (const [unit, btn] of toolButtons) {
|
||||
btn.classList.toggle('active', unit === tool)
|
||||
|
|
@ -272,6 +277,23 @@ function update(): void {
|
|||
renderHint()
|
||||
}
|
||||
|
||||
/** Gibt es noch einen Zug, der Gold bringt? (je Spielstand einmal berechnet) */
|
||||
let gainCache: boolean | null = null
|
||||
function gainLeft(): boolean {
|
||||
if (gainCache !== null) return gainCache
|
||||
gainCache = game.moves.length === 0
|
||||
for (const unit of UNIT_TYPES) {
|
||||
if (gainCache) break
|
||||
const legal = game.legalMoves(unit)
|
||||
for (let cell = 0; cell < legal.length && !gainCache; cell++) {
|
||||
if (!legal[cell]) continue
|
||||
const p = game.preview(unit, cell)
|
||||
if (p.ok && p.net > 0) gainCache = true
|
||||
}
|
||||
}
|
||||
return gainCache
|
||||
}
|
||||
|
||||
/** Feld, für das gerade eine Vorschau gilt: angetippt (Touch) oder unter der Maus */
|
||||
function activeCell(): number | null {
|
||||
return pendingTouch ?? hovered
|
||||
|
|
@ -320,7 +342,8 @@ function renderHint(): void {
|
|||
)
|
||||
return
|
||||
}
|
||||
if (starsOf(game, day.goals).both) setHint(HINTS.allStars, 'good')
|
||||
if (!gainLeft()) setHint(HINTS.noGain, 'warn')
|
||||
else if (starsOf(game, day.goals).both) setHint(HINTS.allStars, 'good')
|
||||
else if (game.count('HIVEMOTHER') === 0) setHint(HINTS.castle)
|
||||
else if (game.moves.length < 3) setHint(HINTS.farmer)
|
||||
else setHint(HINTS.general)
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ export const HINTS = {
|
|||
general:
|
||||
'Ore ⛰ and herbs 🌿 pay 20 gold. Knights pay double. Keep going until no move is left.',
|
||||
touch: 'Tap again to place.',
|
||||
noGain: 'No move left gains gold – end the game to keep what you have.',
|
||||
allStars: 'All 3 stars! Keep going for more gold – or end the game.',
|
||||
} as const
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue