M10b: bussar, fler sidospår och överstimulerande UI
All checks were successful
release / build-release (push) Successful in 1m36s
All checks were successful
release / build-release (push) Successful in 1m36s
Ett tåg kan vara en buss (vehicle: bus): samma tidtabell, faser, bedömning i nätet och ombordstigning, men ett fordon på en väg i stället för vagnar på räls, hållplatsskylt, "1番" på tavlan, tuta vid inrullning och dörrsignal före avgång. Nätet har tre busslinjer från Narita. Nya sidobanor: 001b Flygbussterminalen (biljettbana med tre bussar) och 003b Harajuku (Yamanote åt rätt eller fel håll runt ringen). Overload-flaggan ger en rullande reklamticker och maximalt med affischer (Ueno, Tokyo). Romaji utan makroner (fonten saknar dem). Skärmdumparna som börjar på bankartan går via titelskärmen. Tester, docs och wiki uppdaterade. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ var tileOrder = []level.Tile{
|
||||
level.LaneLeft, level.LaneRight,
|
||||
level.Wall, level.Wall, level.Wall, // plats 13–15 = affischer (laddas separat som Posters)
|
||||
level.Kiosk,
|
||||
level.Wall, level.Wall, level.Wall, // plats 18–20 = buss, väg, hållplatsskylt (laddas separat)
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -39,6 +40,9 @@ const (
|
||||
railsIndex = 9
|
||||
posterIndex = 14
|
||||
posterCount = 3
|
||||
busIndex = 18
|
||||
roadIndex = 19
|
||||
stopIndex = 20
|
||||
)
|
||||
|
||||
// Assets är allt som laddats från resources/.
|
||||
@@ -50,6 +54,9 @@ type Assets struct {
|
||||
Rails *ebiten.Image // rälsruta (horisontell), roteras för vertikala spår
|
||||
Posters []*ebiten.Image // affischer för visuell röra (ritas över väggrutor)
|
||||
Plane *ebiten.Image // flygplanet i slutscenen
|
||||
Bus *ebiten.Image // bussen (ett fordon, inte vagnar)
|
||||
Road *ebiten.Image // vägruta (horisontell), roteras för vertikala
|
||||
StopSign *ebiten.Image // hållplatsskylt ovanpå busshållplatsen
|
||||
Icon image.Image // fönsterikonen (nil om den saknas)
|
||||
Player [4][3]*ebiten.Image // [riktning: ner, upp, vänster, höger][bildruta: stilla, gå1, gå2]
|
||||
Text map[string]string
|
||||
@@ -78,7 +85,7 @@ func LoadAssets() (*Assets, error) {
|
||||
return nil, fmt.Errorf("tiles.png är %d px bred, behöver minst %d", w, need)
|
||||
}
|
||||
for i, t := range tileOrder {
|
||||
if i == trainIndex || i == railsIndex || (i >= posterIndex && i < posterIndex+posterCount) {
|
||||
if i == trainIndex || i == railsIndex || (i >= posterIndex && i < posterIndex+posterCount) || i >= busIndex {
|
||||
continue
|
||||
}
|
||||
a.Tiles[t] = sub(i)
|
||||
@@ -88,6 +95,7 @@ func LoadAssets() (*Assets, error) {
|
||||
}
|
||||
a.Train = sub(trainIndex)
|
||||
a.Rails = sub(railsIndex)
|
||||
a.Bus, a.Road, a.StopSign = sub(busIndex), sub(roadIndex), sub(stopIndex)
|
||||
for i := 0; i < posterCount; i++ {
|
||||
a.Posters = append(a.Posters, sub(posterIndex+i))
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ const (
|
||||
SoundLose = "lose"
|
||||
SoundStaff = "staff"
|
||||
SoundPlane = "plane"
|
||||
SoundBusHorn = "bus-horn"
|
||||
)
|
||||
|
||||
// StationMelodies är avgångsmelodierna; varje station har sin (level.Melody
|
||||
@@ -57,7 +58,7 @@ var StationMelodies = []string{"melody-a", "melody-b", "melody-c", "melody-d"}
|
||||
// AllSounds är alla klipp som måste finnas i resources/sound.
|
||||
func AllSounds() []string {
|
||||
return append([]string{SoundApproach, SoundAnnounce, SoundDoors, SoundChatter, SoundMusicMap, SoundGateBeep, SoundGateDeny,
|
||||
SoundKiosk, SoundToilet, SoundLearn, SoundConfirm, SoundCancel, SoundTransfer, SoundWin, SoundLose, SoundStaff, SoundPlane},
|
||||
SoundKiosk, SoundToilet, SoundLearn, SoundConfirm, SoundCancel, SoundTransfer, SoundWin, SoundLose, SoundStaff, SoundPlane, SoundBusHorn},
|
||||
StationMelodies...)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ func (s *LevelScene) drawNPCs(g *Game, screen *ebiten.Image, ox, oy float64) {
|
||||
func (s *LevelScene) buildPosters() {
|
||||
s.posters = map[level.Point]int{}
|
||||
l := s.run.Level
|
||||
if l.Clutter == 0 {
|
||||
if s.clutterLevel() == 0 {
|
||||
return
|
||||
}
|
||||
r := s.run.Seed.Derive("posters").New()
|
||||
chance := 0.12 * float64(l.Clutter)
|
||||
chance := 0.12 * float64(s.clutterLevel())
|
||||
for z := 0; z < l.NumFloors(); z++ {
|
||||
for y := 0; y < l.Height(); y++ {
|
||||
for x := 0; x < l.Width(); x++ {
|
||||
|
||||
@@ -58,6 +58,7 @@ type LevelScene struct {
|
||||
// Tåg och effekter (M7b).
|
||||
tracks []trackInfo
|
||||
rails map[level.Point]bool
|
||||
roads map[level.Point]bool // vägrutor för bussar (ritas med vägsprite)
|
||||
lastPhase map[level.Tile]level.Phase
|
||||
particles []particle
|
||||
rng *rand.Rand // bara för partiklar (ingen spellogik)
|
||||
@@ -299,7 +300,7 @@ func (s *LevelScene) Draw(g *Game, screen *ebiten.Image) {
|
||||
for y := y0; y < y1; y++ {
|
||||
for x := x0; x < x1; x++ {
|
||||
p := level.Point{X: x, Y: y, Z: z}
|
||||
if s.rails[p] {
|
||||
if s.rails[p] || s.roads[p] {
|
||||
s.drawRails(g, screen, p, ox, oy)
|
||||
continue
|
||||
}
|
||||
@@ -358,6 +359,7 @@ func (s *LevelScene) Draw(g *Game, screen *ebiten.Image) {
|
||||
s.drawIndicator(screen, ox, oy)
|
||||
|
||||
s.drawHUD(g, screen)
|
||||
s.drawTicker(g, screen)
|
||||
s.drawTip(g, screen)
|
||||
if r := s.run; r.TransferAt >= 0 && r.Time-r.TransferAt < transferBannerSec && r.Mini == nil && r.Outcome == sim.Ongoing {
|
||||
txt := g.Assets.T("hud.transfer_done")
|
||||
|
||||
@@ -69,7 +69,7 @@ func (m *MapScene) nodes() ([]mapNode, map[string][]mapNode) {
|
||||
}
|
||||
mains = append(mains, mapNode{l, x, y})
|
||||
for k, s := range m.sides[l.ID] {
|
||||
sides[l.ID] = append(sides[l.ID], mapNode{s, x + 12 + k*18, y - 40})
|
||||
sides[l.ID] = append(sides[l.ID], mapNode{s, x + 12 + k*18, y - 28})
|
||||
}
|
||||
}
|
||||
return mains, sides
|
||||
|
||||
53
internal/game/ticker.go
Normal file
53
internal/game/ticker.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/vector"
|
||||
)
|
||||
|
||||
// Överstimulerande UI (level.Overload): en rullande reklamticker i
|
||||
// blinkande färger under HUD:en, och fler affischer på väggarna. Texten är
|
||||
// reklamfraser som inte betyder något för spelet – det är poängen.
|
||||
var adPhrases = []string{"大セール 半額!", "新発売 ラーメン", "免税 お土産", "駅弁 人気No.1", "本日限り 特価", "ポイント2倍", "新宿 ショッピング", "温泉 旅行 キャンペーン"}
|
||||
|
||||
const tickerSpeed = 30.0 // px/s
|
||||
|
||||
// drawTicker ritar reklamtickern (bara med Overload och när inget annat
|
||||
// ligger där).
|
||||
func (s *LevelScene) drawTicker(g *Game, screen *ebiten.Image) {
|
||||
r := s.run
|
||||
if !r.Level.Overload || r.Mini != nil || r.Outcome != 0 || s.tips.current != "" {
|
||||
return
|
||||
}
|
||||
a := g.Assets
|
||||
text := strings.Join(adPhrases, " ★ ") + " ★ "
|
||||
w := a.Width(text)
|
||||
if w == 0 {
|
||||
return
|
||||
}
|
||||
y := 26
|
||||
blink := math.Mod(r.Time, 1.0) < 0.5
|
||||
bg, fg := color.RGBA{120, 30, 60, 230}, color.RGBA{255, 230, 120, 255}
|
||||
if blink {
|
||||
bg, fg = color.RGBA{40, 60, 140, 230}, color.RGBA{255, 255, 255, 255}
|
||||
}
|
||||
vector.DrawFilledRect(screen, 0, float32(y), ScreenW, LineH+2, bg, false)
|
||||
x := ScreenW - int(math.Mod(r.Time*tickerSpeed, float64(w+ScreenW)))
|
||||
for _, sx := range []int{x, x + w} {
|
||||
if sx < ScreenW && sx+w > 0 {
|
||||
a.Draw(screen, text, sx, y+1, fg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clutterLevel är den visuella röran: banans clutter, maximal med Overload.
|
||||
func (s *LevelScene) clutterLevel() int {
|
||||
if s.run.Level.Overload {
|
||||
return 3
|
||||
}
|
||||
return s.run.Level.Clutter
|
||||
}
|
||||
@@ -31,15 +31,21 @@ type trackInfo struct {
|
||||
platform level.Point // perrongrutan
|
||||
track level.Point // rälsrutan bortom kanten
|
||||
horizontal bool // rälsens riktning
|
||||
bus bool // buss: väg och ett fordon i stället för räls och vagnar
|
||||
}
|
||||
|
||||
func (s *LevelScene) buildTracks() {
|
||||
s.tracks = nil
|
||||
s.rails = map[level.Point]bool{}
|
||||
s.roads = map[level.Point]bool{}
|
||||
for _, t := range level.PlatformTiles {
|
||||
for _, p := range s.run.Level.Find(t) {
|
||||
tt, horizontal := s.run.Level.TrackTile(p)
|
||||
s.tracks = append(s.tracks, trackInfo{tile: t, platform: p, track: tt, horizontal: horizontal})
|
||||
bus := false
|
||||
if tr := s.run.Level.TrainAt(t); tr != nil && tr.IsBus() {
|
||||
bus = true
|
||||
}
|
||||
s.tracks = append(s.tracks, trackInfo{tile: t, platform: p, track: tt, horizontal: horizontal, bus: bus})
|
||||
out := level.Point{X: tt.X - p.X, Y: tt.Y - p.Y} // riktningen bort från perrongen
|
||||
for k := -railsReach; k <= railsReach; k++ {
|
||||
c := tt
|
||||
@@ -51,7 +57,11 @@ func (s *LevelScene) buildTracks() {
|
||||
beyond := level.Point{X: c.X + out.X, Y: c.Y + out.Y, Z: c.Z}
|
||||
// Räls på väggrutor längs spåret, så länge det är vägg (eller kartkant) bortom dem.
|
||||
if s.run.Level.At(c) == level.Wall && s.run.Level.At(beyond) == level.Wall {
|
||||
s.rails[c] = true
|
||||
if bus {
|
||||
s.roads[c] = true
|
||||
} else {
|
||||
s.rails[c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +97,11 @@ func (s *LevelScene) drawRails(g *Game, screen *ebiten.Image, c level.Point, ox,
|
||||
op.GeoM.Translate(TileSize/2, TileSize/2)
|
||||
}
|
||||
op.GeoM.Translate(ox+float64(c.X*TileSize), oy+float64(c.Y*TileSize))
|
||||
screen.DrawImage(g.Assets.Rails, &op)
|
||||
img := g.Assets.Rails
|
||||
if s.roads[c] {
|
||||
img = g.Assets.Road
|
||||
}
|
||||
screen.DrawImage(img, &op)
|
||||
}
|
||||
|
||||
// drawTrains ritar tågen i rätt läge för sin fas.
|
||||
@@ -98,6 +112,11 @@ func (s *LevelScene) drawTrains(g *Game, screen *ebiten.Image, ox, oy float64) {
|
||||
continue // tågen på andra våningar syns inte härifrån
|
||||
}
|
||||
phase, prog := s.run.PlatformPhase(tr.tile)
|
||||
if tr.bus { // hållplatsskylten står på hållplatsen
|
||||
var op ebiten.DrawImageOptions
|
||||
op.GeoM.Translate(ox+float64(tr.platform.X*TileSize), oy+float64(tr.platform.Y*TileSize))
|
||||
screen.DrawImage(g.Assets.StopSign, &op)
|
||||
}
|
||||
// Strålkastare när tåget är på väg in: ett sken från det håll det kommer.
|
||||
if phase == level.Approaching {
|
||||
s.drawHeadlight(screen, tr, prog, ox, oy)
|
||||
@@ -106,8 +125,12 @@ func (s *LevelScene) drawTrains(g *Game, screen *ebiten.Image, ox, oy float64) {
|
||||
if !show {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < trainCars; k++ {
|
||||
d := off + float64(k-trainCars/2)
|
||||
cars, sprite := trainCars, g.Assets.Train
|
||||
if tr.bus {
|
||||
cars, sprite = 1, g.Assets.Bus
|
||||
}
|
||||
for k := 0; k < cars; k++ {
|
||||
d := off + float64(k-cars/2)
|
||||
var op ebiten.DrawImageOptions
|
||||
x, y := float64(tr.track.X*TileSize), float64(tr.track.Y*TileSize)
|
||||
if tr.horizontal {
|
||||
@@ -119,7 +142,7 @@ func (s *LevelScene) drawTrains(g *Game, screen *ebiten.Image, ox, oy float64) {
|
||||
op.GeoM.Translate(TileSize/2, TileSize/2)
|
||||
}
|
||||
op.GeoM.Translate(ox+math.Round(x), oy+math.Round(y))
|
||||
screen.DrawImage(g.Assets.Train, &op)
|
||||
screen.DrawImage(sprite, &op)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,14 +185,19 @@ func (s *LevelScene) updateEffects(g *Game) {
|
||||
s.lastPhase[tr.tile] = phase
|
||||
dist := math.Hypot(float64(tr.platform.X*TileSize)-px, float64(tr.platform.Y*TileSize)-py) / TileSize
|
||||
mask := noiseMask(r.Level.Noise)
|
||||
switch phase {
|
||||
case level.Approaching: // ankomstjingeln: tåget är på väg
|
||||
switch {
|
||||
case tr.bus && phase == level.Arriving: // bussen tutar när den svänger in
|
||||
g.Audio.Play(SoundBusHorn, volumeAt(dist)*mask)
|
||||
case tr.bus && phase == level.Closing:
|
||||
g.Audio.Play(SoundDoors, volumeAt(dist)*mask)
|
||||
case tr.bus:
|
||||
case phase == level.Approaching: // ankomstjingeln: tåget är på väg
|
||||
g.Audio.Play(SoundApproach, volumeAt(dist)*mask)
|
||||
case level.Arriving: // ding-dong när det rullar in
|
||||
case phase == level.Arriving: // ding-dong när det rullar in
|
||||
g.Audio.Play(SoundAnnounce, volumeAt(dist)*mask)
|
||||
case level.Closing: // stationens avgångsmelodi innan dörrarna stängs
|
||||
case phase == level.Closing: // stationens avgångsmelodi innan dörrarna stängs
|
||||
g.Audio.Play(MelodyFor(r.Level), volumeAt(dist)*mask)
|
||||
case level.Leaving: // dörrsignalen när det går
|
||||
case phase == level.Leaving: // dörrsignalen när det går
|
||||
g.Audio.Play(SoundDoors, volumeAt(dist)*mask)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ type Train struct {
|
||||
Correct bool `json:"correct"` // tar spelaren till rätt resmål (räknas ut från nätet när banan har station/to)
|
||||
LineID string `json:"lineId"` // linjen i linjenätet (resources/data/network.json)
|
||||
Terminus string `json:"terminus"` // en station i färdriktningen (nätets id) – avgör riktningen
|
||||
Vehicle string `json:"vehicle"` // "" = tåg, "bus" = buss (väg i stället för räls, hållplats i stället för perrong)
|
||||
Crowded bool `json:"crowded"` // fullt tåg: minispel för att få plats (gäller alla vagnar)
|
||||
Cars int `json:"cars"` // antal vagnar (0 = DefaultCars)
|
||||
WomenOnlyCar int `json:"womenOnlyCar"` // 1-baserat vagnnummer för kvinnovagn, 0 = ingen
|
||||
@@ -269,6 +270,7 @@ type Level struct {
|
||||
SeatSelection bool `json:"seatSelection"` // biljettköpet fortsätter med sittplatsval efter sällskapets önskemål
|
||||
OneWayGates bool `json:"oneWayGates"` // spärren släpper inte ut en igen förrän man åkt; personal vid spärren låser upp (tar tid)
|
||||
Melody string `json:"melody"` // stationens avgångsmelodi: "a".."d" (tomt = vald efter id)
|
||||
Overload bool `json:"overload"` // överstimulerande UI: reklamticker, blinkande reklam, extra affischer
|
||||
FareYen int `json:"fareYen"` // vad spärren drar från kortet (0 = standard)
|
||||
Grid []string `json:"grid,omitempty"` // envåningsbana (kompatibilitet) – blir Floors[0]
|
||||
Floors []Storey `json:"floors,omitempty"` // flervåningsbana; alla våningar lika stora
|
||||
@@ -466,8 +468,14 @@ func (l *Level) Validate() error {
|
||||
if tr.Correct {
|
||||
correct++
|
||||
}
|
||||
if tr.Vehicle != "" && tr.Vehicle != "bus" {
|
||||
return fmt.Errorf("level %s: tåg %d har okänt fordon %q (tomt eller bus)", l.ID, i, tr.Vehicle)
|
||||
}
|
||||
if tr.Cars == 0 {
|
||||
tr.Cars = DefaultCars
|
||||
if tr.IsBus() {
|
||||
tr.Cars = 1
|
||||
}
|
||||
}
|
||||
if tr.Cars < 1 || tr.Cars > MaxCars {
|
||||
return fmt.Errorf("level %s: tåg %d har %d vagnar (1–%d)", l.ID, i, tr.Cars, MaxCars)
|
||||
@@ -720,11 +728,18 @@ func (l *Level) Unreachable() []Point {
|
||||
return out
|
||||
}
|
||||
|
||||
// BoardText är avgångstavlans text på japanska, t.ex. "2番線 成田エクスプレス 新宿方面".
|
||||
// BoardText är avgångstavlans text på japanska, t.ex. "2番線 成田エクスプレス 新宿方面"
|
||||
// (för bussar "1番 リムジンバス 新宿方面": hållplatsnummer i stället för spår).
|
||||
func (tr *Train) BoardText() string {
|
||||
if tr.IsBus() {
|
||||
return tr.Track + "番 " + tr.Line.Get("ja") + " " + tr.Destination.Get("ja") + "方面"
|
||||
}
|
||||
return tr.Track + "番線 " + tr.Line.Get("ja") + " " + tr.Destination.Get("ja") + "方面"
|
||||
}
|
||||
|
||||
// IsBus rapporterar om fordonet är en buss.
|
||||
func (tr *Train) IsBus() bool { return tr.Vehicle == "bus" }
|
||||
|
||||
// TrackTile är rutan "bortom perrongkanten" där rälsen går: första väggruta
|
||||
// nedanför, till höger, till vänster eller ovanför perrongen. horizontal
|
||||
// anger om rälsen (och tågets rörelse) går i sidled.
|
||||
|
||||
@@ -838,3 +838,24 @@ func TestToiletSides(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBusVehicleAndBoardText(t *testing.T) {
|
||||
src := `{"id":"bus","name":{"sv":"x"},"difficulty":1,"destination":{"ja":"新宿"},
|
||||
"grid":["#######","#S.GP.#","#######"],
|
||||
"trains":[{"platform":"P","track":"1","line":{"ja":"リムジンバス"},"destination":{"ja":"新宿"},"correct":true,"vehicle":"bus"}]}`
|
||||
l, err := Parse([]byte(src))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tr := &l.Trains[0]
|
||||
if !tr.IsBus() || tr.Cars != 1 || tr.BoardText() != "1番 リムジンバス 新宿方面" {
|
||||
t.Fatalf("buss: cars=%d board=%q", tr.Cars, tr.BoardText())
|
||||
}
|
||||
if _, err := Parse([]byte(strings.Replace(src, `"vehicle":"bus"`, `"vehicle":"tram"`, 1))); err == nil {
|
||||
t.Fatal("okänt fordon ska ge fel")
|
||||
}
|
||||
train, _ := Parse([]byte(strings.Replace(src, `,"vehicle":"bus"`, ``, 1)))
|
||||
if train.Trains[0].IsBus() || train.Trains[0].Cars != DefaultCars || train.Trains[0].BoardText() != "1番線 リムジンバス 新宿方面" {
|
||||
t.Fatal("utan vehicle är det ett tåg")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,3 +169,20 @@ func TestShippedNetwork(t *testing.T) {
|
||||
t.Errorf("Marunouchi via city = %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShippedBusLines(t *testing.T) {
|
||||
dir, err := res.Path("data")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n, err := LoadFile(filepath.Join(dir, "network.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v := n.Judge("limousine-shinjuku", "narita-airport", "shinjuku", "shinjuku"); v != Direct {
|
||||
t.Errorf("flygbussen mot Shinjuku = %v", v)
|
||||
}
|
||||
if v := n.Judge("limousine-yokohama", "narita-airport", "yokohama", "shinjuku"); v != NoService {
|
||||
t.Errorf("flygbussen mot Yokohama för den som ska till Shinjuku = %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,3 +126,36 @@ func TestTerminalLines(t *testing.T) {
|
||||
t.Fatal("okopplad bana har ingen terminal")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBusTerminalFlow: flygbussterminalen är en biljettbana med bussar –
|
||||
// köp biljett till Shinjuku, gå till hållplats 1 och åk.
|
||||
func TestBusTerminalFlow(t *testing.T) {
|
||||
l := loadLevel(t, "001b-flygbussen")
|
||||
if !l.TicketRequired || !l.Trains[0].IsBus() || l.Trains[0].Cars != 1 {
|
||||
t.Fatal("001b ska vara en biljettbana med bussar")
|
||||
}
|
||||
r := NewRun(l, RunOptions{Dict: loadDict(t), Seed: rng.FromInt(3)})
|
||||
r.Party.nextEventAt = 1e9
|
||||
r.NPCs = nil
|
||||
walk(t, r, pathTo(r, l.Find(level.TicketMachine)[0]))
|
||||
r.Step(frame, None, true)
|
||||
tk, ok := r.Mini.(*minigame.Ticket)
|
||||
if !ok {
|
||||
t.Fatalf("ingen biljettautomat (kind=%v)", r.MiniKind)
|
||||
}
|
||||
for tk.Options[tk.Cursor].Dest != "新宿" {
|
||||
r.StepMini(frame, minigame.Input{Move: 1})
|
||||
}
|
||||
r.StepMini(frame, minigame.Input{Confirm: true})
|
||||
if r.Wallet.Ticket != "新宿" {
|
||||
t.Fatalf("biljett=%q", r.Wallet.Ticket)
|
||||
}
|
||||
tr := boardAt(t, r, level.Platform)
|
||||
if !tr.IsBus() || tr.Verdict != nav.Direct {
|
||||
t.Fatalf("hållplats 1: %v %v", tr.IsBus(), tr.Verdict)
|
||||
}
|
||||
ride(t, r)
|
||||
if r.Outcome != Won {
|
||||
t.Fatalf("outcome=%v (%s)", r.Outcome, r.LostReason)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user