M9a: stationer i flera våningar med trappor
All checks were successful
release / build-release (push) Successful in 1m34s

- level: Point har Z; banor kan ha floors (lika stora rutnät med namn),
  gamla grid-banor läses som en våning; trappor U/D på samma x,y en våning
  upp/ner valideras parvis; Neighbors ger grannar över våningar så att
  Path, lösbarhet, spärregel och Unreachable fungerar; skyltar har z
- sim: att kliva på en trappa flyttar spelaren till andra änden
  (FloorChanges); dimman är per våning och avslöjar trappans andra ände;
  tåg hörs/syns bara på egen våning
- game: bara spelarens våning ritas (följare på andra våningar döljs),
  HUD och minikarta visar våningens namn, trappgrafik i genart och färg på
  minikartan
- bana 004 Tokyo (svårighet 3, tre i sällskapet): start under mark på B1,
  trappa upp till 1F med perronger; generatorn gör våningar med trappor
  som flaskhalsar; ordboken utökad
- testbotar och tools/shots förstår trappor; två våningsbilder
- docs/README/wiki uppdaterade

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 11:54:07 +02:00
parent ef6cfaccc8
commit 8fca14e42d
23 changed files with 704 additions and 152 deletions

View File

@@ -29,6 +29,8 @@ var minimapColors = map[level.Tile]color.RGBA{
level.Sign: {90, 140, 230, 255},
level.Toilet: {235, 240, 250, 255},
level.Kiosk: {228, 59, 68, 255},
level.StairsUp: {200, 150, 255, 255},
level.StairsDown: {150, 100, 220, 255},
}
// minimapScale väljer pixlar per ruta så att kartan ryms i ungefär en
@@ -80,8 +82,16 @@ func (s *LevelScene) drawMinimap(g *Game, screen *ebiten.Image, box image.Rectan
}
sort.Slice(deps, func(i, j int) bool { return deps[i].track < deps[j].track })
z := r.Player.Tile.Z
floorLabel := ""
if l.NumFloors() > 1 {
floorLabel = l.FloorName(z)
}
w := max(mapW, 44) + 6
h := mapH + 6 + len(deps)*LineH
if floorLabel != "" {
h += LineH
}
px, py := r.Player.WorldPos(TileSize)
ox, oy := s.cam.Offset()
playerRect := image.Rect(int(px+ox), int(py+oy), int(px+ox)+TileSize, int(py+oy)+TileSize)
@@ -89,13 +99,17 @@ func (s *LevelScene) drawMinimap(g *Game, screen *ebiten.Image, box image.Rectan
vector.DrawFilledRect(screen, float32(rc.Min.X), float32(rc.Min.Y), float32(w), float32(h), colPanel, false)
x0, y0 := rc.Min.X+3, rc.Min.Y+3
if floorLabel != "" {
a.Draw(screen, floorLabel, x0, y0, colKnown)
y0 += LineH
}
for y := 0; y < l.Height(); y++ {
for x := 0; x < l.Width(); x++ {
p := level.Point{X: x, Y: y}
p := level.Point{X: x, Y: y, Z: z}
if !r.Fog.Visible(l, p) {
continue
}
t := l.At(x, y)
t := l.At(p)
c := minimapColors[t]
if (t == level.Platform || t == level.WrongPlatform) && r.TrainVisible(t) {
c = color.RGBA{255, 255, 255, 255} // tåget är inne
@@ -106,6 +120,9 @@ func (s *LevelScene) drawMinimap(g *Game, screen *ebiten.Image, box image.Rectan
// Sällskapet: följarna i sina toner, spelaren blinkande vit.
for i := len(r.Party.Followers()); i >= 1; i-- {
from, _ := r.Party.FollowerTiles(i)
if from.Z != z {
continue
}
tint := memberTints[i%len(memberTints)]
vector.DrawFilledRect(screen, float32(x0+from.X*sc), float32(y0+from.Y*sc), float32(sc), float32(sc),
color.RGBA{uint8(255 * tint[0]), uint8(255 * tint[1]), uint8(255 * tint[2]), 255}, false)