All checks were successful
release / build-release (push) Successful in 1m34s
internal/endless lottar mål ur en seed: en av storyns nätkopplade stationer (aldrig samma två gånger i rad) med ett resmål som minst ett tåg går rakt till men inte alla; banan kopieras, bedöms om mot nätet, sällskapet växer var tredje mål och tidsgränsen krymper. O på bankartan (eller -endless) startar en omgång; klarade mål ger poäng och XP, Enter ger nästa mål, förlust eller Esc avslutar och omgången hamnar i sparfilens poänglista (fem bästa). G två gånger startar New Game+: items, banresultat, pengar och debuffar nollställs, skills, XP och japanskan behålls, sällskapet är en person större per varv. Docs, wiki, tester och skärmdumpar uppdaterade. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
177 lines
6.6 KiB
Go
177 lines
6.6 KiB
Go
package game
|
|
|
|
import (
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
|
|
|
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/sim"
|
|
)
|
|
|
|
const stickDeadzone = 0.5
|
|
|
|
// dirInput returnerar hållen riktning från tangentbord (pilar/WASD) eller
|
|
// gamepad (d-pad / vänster spak). None om inget hålls.
|
|
func dirInput() sim.Dir {
|
|
if virtual.held != sim.None {
|
|
return virtual.held
|
|
}
|
|
switch {
|
|
case ebiten.IsKeyPressed(ebiten.KeyArrowUp) || ebiten.IsKeyPressed(ebiten.KeyW):
|
|
return sim.Up
|
|
case ebiten.IsKeyPressed(ebiten.KeyArrowDown) || ebiten.IsKeyPressed(ebiten.KeyS):
|
|
return sim.Down
|
|
case ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || ebiten.IsKeyPressed(ebiten.KeyA):
|
|
return sim.Left
|
|
case ebiten.IsKeyPressed(ebiten.KeyArrowRight) || ebiten.IsKeyPressed(ebiten.KeyD):
|
|
return sim.Right
|
|
}
|
|
for _, id := range ebiten.AppendGamepadIDs(nil) {
|
|
if !ebiten.IsStandardGamepadLayoutAvailable(id) {
|
|
continue
|
|
}
|
|
switch {
|
|
case ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftTop):
|
|
return sim.Up
|
|
case ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftBottom):
|
|
return sim.Down
|
|
case ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftLeft):
|
|
return sim.Left
|
|
case ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftRight):
|
|
return sim.Right
|
|
}
|
|
x := ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickHorizontal)
|
|
y := ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickVertical)
|
|
switch {
|
|
case y < -stickDeadzone:
|
|
return sim.Up
|
|
case y > stickDeadzone:
|
|
return sim.Down
|
|
case x < -stickDeadzone:
|
|
return sim.Left
|
|
case x > stickDeadzone:
|
|
return sim.Right
|
|
}
|
|
}
|
|
return sim.None
|
|
}
|
|
|
|
// confirmJustPressed: Enter/mellanslag eller gamepadens nedre knapp (A/kryss).
|
|
func confirmJustPressed() bool {
|
|
if virtual.pressed["enter"] {
|
|
return true
|
|
}
|
|
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeySpace) {
|
|
return true
|
|
}
|
|
return gamepadJustPressed(ebiten.StandardGamepadButtonRightBottom)
|
|
}
|
|
|
|
// backJustPressed: Escape eller gamepadens högra knapp (B/cirkel).
|
|
func backJustPressed() bool {
|
|
return virtual.pressed["esc"] || inpututil.IsKeyJustPressed(ebiten.KeyEscape) || gamepadJustPressed(ebiten.StandardGamepadButtonRightRight)
|
|
}
|
|
|
|
// helpJustPressed: H eller gamepadens övre knapp (Y/triangel) = fråga om hjälp.
|
|
func helpJustPressed() bool {
|
|
return virtual.pressed["h"] || inpututil.IsKeyJustPressed(ebiten.KeyH) || gamepadJustPressed(ebiten.StandardGamepadButtonRightTop)
|
|
}
|
|
|
|
// wordsJustPressed: L = ordlistan/språkträdet.
|
|
func wordsJustPressed() bool {
|
|
return virtual.pressed["l"] || inpututil.IsKeyJustPressed(ebiten.KeyL) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftRight)
|
|
}
|
|
|
|
// miniMoveXY: just-tryck på pil/WASD/d-pad som (x, y) i -1/0/+1.
|
|
func miniMoveXY() (x, y int) {
|
|
switch {
|
|
case virtual.pressed["left"] || inpututil.IsKeyJustPressed(ebiten.KeyArrowLeft) || inpututil.IsKeyJustPressed(ebiten.KeyA) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftLeft):
|
|
x = -1
|
|
case virtual.pressed["right"] || inpututil.IsKeyJustPressed(ebiten.KeyArrowRight) || inpututil.IsKeyJustPressed(ebiten.KeyD) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftRight):
|
|
x = 1
|
|
}
|
|
switch {
|
|
case virtual.pressed["up"] || inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftTop):
|
|
y = -1
|
|
case virtual.pressed["down"] || inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftBottom):
|
|
y = 1
|
|
}
|
|
return x, y
|
|
}
|
|
|
|
// confirmHeld: Enter/mellanslag eller A hålls nere (sedelinmatning).
|
|
func confirmHeld() bool {
|
|
if virtual.pressed["enter"] || virtual.holdEnter {
|
|
return true
|
|
}
|
|
if ebiten.IsKeyPressed(ebiten.KeyEnter) || ebiten.IsKeyPressed(ebiten.KeySpace) {
|
|
return true
|
|
}
|
|
for _, id := range ebiten.AppendGamepadIDs(nil) {
|
|
if ebiten.IsStandardGamepadLayoutAvailable(id) && ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightBottom) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// skillsJustPressed: T = skillträdet.
|
|
func skillsJustPressed() bool { return virtual.pressed["t"] || inpututil.IsKeyJustPressed(ebiten.KeyT) }
|
|
|
|
// itemsJustPressed: I = garderoben/items.
|
|
func itemsJustPressed() bool { return virtual.pressed["i"] || inpututil.IsKeyJustPressed(ebiten.KeyI) }
|
|
|
|
// shopJustPressed: B = butiken i kiosken.
|
|
func shopJustPressed() bool { return virtual.pressed["b"] || inpututil.IsKeyJustPressed(ebiten.KeyB) }
|
|
|
|
// phoneJustPressed: P = kortet i telefonen av/på (meny).
|
|
func phoneJustPressed() bool { return virtual.pressed["p"] || inpututil.IsKeyJustPressed(ebiten.KeyP) }
|
|
|
|
// endlessJustPressed: O startar oändligt läge (när storyn är klar).
|
|
func endlessJustPressed() bool {
|
|
return virtual.pressed["o"] || inpututil.IsKeyJustPressed(ebiten.KeyO)
|
|
}
|
|
|
|
// ngPlusJustPressed: G (två gånger) startar New Game+.
|
|
func ngPlusJustPressed() bool { return virtual.pressed["g"] || inpututil.IsKeyJustPressed(ebiten.KeyG) }
|
|
|
|
// miniMoveXYAny rapporterar om någon pil just trycktes (för att avbryta en bekräftelse).
|
|
func miniMoveXYAny() bool {
|
|
x, y := miniMoveXY()
|
|
return x != 0 || y != 0
|
|
}
|
|
|
|
// modeJustPressed: N växlar navigeringsläge (lista/skyltar) på bankartan.
|
|
func modeJustPressed() bool { return virtual.pressed["n"] || inpututil.IsKeyJustPressed(ebiten.KeyN) }
|
|
|
|
// mapJustPressed: M eller gamepadens vänstra mittknapp (Back/Select) = minikartan av/på.
|
|
func mapJustPressed() bool {
|
|
return virtual.pressed["m"] || inpututil.IsKeyJustPressed(ebiten.KeyM) || gamepadJustPressed(ebiten.StandardGamepadButtonCenterLeft)
|
|
}
|
|
|
|
// menuMove returnerar -1/+1 när användaren just tryckte upp/ner i en meny.
|
|
func menuMove() int {
|
|
switch {
|
|
case virtual.pressed["up"]:
|
|
return -1
|
|
case virtual.pressed["down"]:
|
|
return 1
|
|
case inpututil.IsKeyJustPressed(ebiten.KeyArrowUp) || inpututil.IsKeyJustPressed(ebiten.KeyW) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftTop):
|
|
return -1
|
|
case inpututil.IsKeyJustPressed(ebiten.KeyArrowDown) || inpututil.IsKeyJustPressed(ebiten.KeyS) || gamepadJustPressed(ebiten.StandardGamepadButtonLeftBottom):
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func gamepadJustPressed(b ebiten.StandardGamepadButton) bool {
|
|
for _, id := range ebiten.AppendGamepadIDs(nil) {
|
|
if ebiten.IsStandardGamepadLayoutAvailable(id) && inpututil.IsStandardGamepadButtonJustPressed(id, b) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// inpututil_R: R = spela om banan.
|
|
func inpututil_R() bool { return virtual.pressed["r"] || inpututil.IsKeyJustPressed(ebiten.KeyR) }
|