M9b: folk, filer, reklam, sorl och vagnval
All checks were successful
release / build-release (push) Successful in 1m33s

Folk på stationen (NPC:er som vandrar, kliver av tåg och går mot
utgången, blockerar spelaren men inte varandra), vänster-/högerfiler
som bromsar på fel sida, bredare gångar, reklamaffischer (clutter),
japanskt sorl i loop (noise), vagnval med kvinnovagn (stort avdrag med
man i sällskapet, tidsstyrd), kömarkeringar på perrongen, trängsel per
vagn (bonus för tom vagn, svettig-debuff och svårare resa i full vagn,
släpp förbi passagerare) och att folk kliver av innan man får gå på.
Ny bana 005 Ueno. Skärmdumpsverktyget kan filtrera på bana/skript.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 12:33:44 +02:00
parent 8fca14e42d
commit de61568e44
49 changed files with 1568 additions and 136 deletions

View File

@@ -17,6 +17,7 @@ import (
type Audio struct {
ctx *audio.Context
clips map[string][]byte // avkodad PCM (16-bit stereo LE) per klipp
loop *audio.Player // pågående bakgrundsloop (bakgrundsprat)
}
const sampleRate = 44100
@@ -25,6 +26,7 @@ const sampleRate = 44100
const (
SoundApproach = "melody-approach"
SoundDoors = "door-chime"
SoundChatter = "chatter"
)
// AudibleTiles är hur många rutor bort man hör perrongens ljud.
@@ -36,7 +38,7 @@ func newAudio(mute bool) (*Audio, error) {
return nil, nil
}
a := &Audio{ctx: audio.NewContext(sampleRate), clips: map[string][]byte{}}
for _, name := range []string{SoundApproach, SoundDoors} {
for _, name := range []string{SoundApproach, SoundDoors, SoundChatter} {
b, err := res.ReadFile("sound", name+".wav")
if err != nil {
return nil, err
@@ -68,5 +70,34 @@ func (a *Audio) Play(name string, volume float64) {
p.Play()
}
// Loop startar (eller byter) bakgrundsloopen med given volym; 0 stoppar.
func (a *Audio) Loop(name string, volume float64) {
if a == nil {
return
}
a.StopLoop()
pcm, ok := a.clips[name]
if !ok || volume <= 0 {
return
}
stream := audio.NewInfiniteLoop(bytes.NewReader(pcm), int64(len(pcm)))
p, err := a.ctx.NewPlayer(stream)
if err != nil {
return
}
p.SetVolume(math.Min(1, volume))
p.Play()
a.loop = p
}
// StopLoop stoppar bakgrundsloopen.
func (a *Audio) StopLoop() {
if a == nil || a.loop == nil {
return
}
a.loop.Close()
a.loop = nil
}
// volumeAt ger volym efter avstånd i rutor.
func volumeAt(dist float64) float64 { return math.Max(0, 1-dist/AudibleTiles) }