mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 07:27:19 -05:00
Sound engine and sound environments (#652)
* Working sound engine and sound environments * Clean up sounds.txt loader * Make global volume settings apply properly Als shuffle some stuff around * Reset sound engine on game unload
This commit is contained in:
parent
78ecc3557e
commit
29ea71489d
@ -36,11 +36,11 @@ type SoundEnvironRecord struct {
|
||||
|
||||
// SoundEnvirons contains the SoundEnviron records
|
||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||
var SoundEnvirons map[string]*SoundEnvironRecord
|
||||
var SoundEnvirons map[int]*SoundEnvironRecord
|
||||
|
||||
// LoadSoundEnvirons loads SoundEnvirons from the supplied file
|
||||
func LoadSoundEnvirons(file []byte) {
|
||||
SoundEnvirons = make(map[string]*SoundEnvironRecord)
|
||||
SoundEnvirons = make(map[int]*SoundEnvironRecord)
|
||||
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
@ -70,7 +70,7 @@ func LoadSoundEnvirons(file []byte) {
|
||||
EAXRoomRoll: d.Number("EAX Room Roll"),
|
||||
EAXAirAbsorb: d.Number("EAX Air Absorb"),
|
||||
}
|
||||
SoundEnvirons[record.Handle] = record
|
||||
SoundEnvirons[record.Index] = record
|
||||
}
|
||||
|
||||
if d.Err != nil {
|
||||
|
@ -2,7 +2,6 @@ package d2datadict
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
)
|
||||
@ -12,69 +11,30 @@ type SoundEntry struct {
|
||||
Handle string
|
||||
Index int
|
||||
FileName string
|
||||
Volume byte
|
||||
GroupSize uint8
|
||||
Volume int
|
||||
GroupSize int
|
||||
Loop bool
|
||||
FadeIn uint8
|
||||
FadeOut uint8
|
||||
DeferInst uint8
|
||||
StopInst uint8
|
||||
Duration uint8
|
||||
Compound int8
|
||||
Reverb bool
|
||||
Falloff uint8
|
||||
Cache uint8
|
||||
FadeIn int
|
||||
FadeOut int
|
||||
DeferInst bool
|
||||
StopInst bool
|
||||
Duration int
|
||||
Compound int
|
||||
Reverb int
|
||||
Falloff int
|
||||
Cache bool
|
||||
AsyncOnly bool
|
||||
Priority uint8
|
||||
Stream uint8
|
||||
Stereo uint8
|
||||
Tracking uint8
|
||||
Solo uint8
|
||||
MusicVol uint8
|
||||
Priority int
|
||||
Stream bool
|
||||
Stereo bool
|
||||
Tracking bool
|
||||
Solo bool
|
||||
MusicVol bool
|
||||
Block1 int
|
||||
Block2 int
|
||||
Block3 int
|
||||
}
|
||||
|
||||
// CreateSoundEntry creates a sound entry based on a sound row on sounds.txt
|
||||
func createSoundEntry(soundLine string) SoundEntry {
|
||||
props := strings.Split(soundLine, "\t")
|
||||
i := -1
|
||||
inc := func() int {
|
||||
i++
|
||||
return i
|
||||
}
|
||||
result := SoundEntry{
|
||||
Handle: props[inc()],
|
||||
Index: d2common.StringToInt(props[inc()]),
|
||||
FileName: props[inc()],
|
||||
Volume: d2common.StringToUint8(props[inc()]),
|
||||
GroupSize: d2common.StringToUint8(props[inc()]),
|
||||
Loop: d2common.StringToUint8(props[inc()]) == 1,
|
||||
FadeIn: d2common.StringToUint8(props[inc()]),
|
||||
FadeOut: d2common.StringToUint8(props[inc()]),
|
||||
DeferInst: d2common.StringToUint8(props[inc()]),
|
||||
StopInst: d2common.StringToUint8(props[inc()]),
|
||||
Duration: d2common.StringToUint8(props[inc()]),
|
||||
Compound: d2common.StringToInt8(props[inc()]),
|
||||
Reverb: d2common.StringToUint8(props[inc()]) == 1,
|
||||
Falloff: d2common.StringToUint8(props[inc()]),
|
||||
Cache: d2common.StringToUint8(props[inc()]),
|
||||
AsyncOnly: d2common.StringToUint8(props[inc()]) == 1,
|
||||
Priority: d2common.StringToUint8(props[inc()]),
|
||||
Stream: d2common.StringToUint8(props[inc()]),
|
||||
Stereo: d2common.StringToUint8(props[inc()]),
|
||||
Tracking: d2common.StringToUint8(props[inc()]),
|
||||
Solo: d2common.StringToUint8(props[inc()]),
|
||||
MusicVol: d2common.StringToUint8(props[inc()]),
|
||||
Block1: d2common.StringToInt(props[inc()]),
|
||||
Block2: d2common.StringToInt(props[inc()]),
|
||||
Block3: d2common.StringToInt(props[inc()]),
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Sounds stores all of the SoundEntries
|
||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||
var Sounds map[string]SoundEntry
|
||||
@ -82,31 +42,53 @@ var Sounds map[string]SoundEntry
|
||||
// LoadSounds loads SoundEntries from sounds.txt
|
||||
func LoadSounds(file []byte) {
|
||||
Sounds = make(map[string]SoundEntry)
|
||||
soundData := strings.Split(string(file), "\r\n")[1:]
|
||||
|
||||
for _, line := range soundData {
|
||||
if line == "" {
|
||||
continue
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
entry := SoundEntry{
|
||||
Handle: d.String("Sound"),
|
||||
Index: d.Number("Index"),
|
||||
FileName: d.String("FileName"),
|
||||
Volume: d.Number("Volume"),
|
||||
GroupSize: d.Number("Group Size"),
|
||||
Loop: d.Bool("Loop"),
|
||||
FadeIn: d.Number("Fade In"),
|
||||
FadeOut: d.Number("Fade Out"),
|
||||
DeferInst: d.Bool("Defer Inst"),
|
||||
StopInst: d.Bool("Stop Inst"),
|
||||
Duration: d.Number("Duration"),
|
||||
Compound: d.Number("Compound"),
|
||||
Reverb: d.Number("Reverb"),
|
||||
Falloff: d.Number("Falloff"),
|
||||
Cache: d.Bool("Cache"),
|
||||
AsyncOnly: d.Bool("Async Only"),
|
||||
Priority: d.Number("Priority"),
|
||||
Stream: d.Bool("Stream"),
|
||||
Stereo: d.Bool("Stereo"),
|
||||
Tracking: d.Bool("Tracking"),
|
||||
Solo: d.Bool("Solo"),
|
||||
MusicVol: d.Bool("Music Vol"),
|
||||
Block1: d.Number("Block 1"),
|
||||
Block2: d.Number("Block 2"),
|
||||
Block3: d.Number("Block 3"),
|
||||
}
|
||||
Sounds[entry.Handle] = entry
|
||||
}
|
||||
|
||||
soundEntry := createSoundEntry(line)
|
||||
soundEntry.FileName = "/data/global/sfx/" + strings.ReplaceAll(soundEntry.FileName, `\`, "/")
|
||||
Sounds[soundEntry.Handle] = soundEntry
|
||||
|
||||
//nolint:gocritic // Debug util code
|
||||
/*
|
||||
// Use the following code to write out the values
|
||||
f, err := os.OpenFile(`C:\Users\lunat\Desktop\D2\sounds.txt`,
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString("\n[" + soundEntry.Handle + "] " + soundEntry.FileName); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*/
|
||||
} //nolint:wsl // Debug util code
|
||||
if d.Err != nil {
|
||||
panic(d.Err)
|
||||
}
|
||||
|
||||
log.Printf("Loaded %d sound definitions", len(Sounds))
|
||||
}
|
||||
|
||||
// SelectSoundByIndex selects a sound by its ID
|
||||
func SelectSoundByIndex(index int) *SoundEntry {
|
||||
for _, el := range Sounds {
|
||||
if el.Index == index {
|
||||
return &el
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ package d2interface
|
||||
// by the asset manager, and set the game engine's volume levels
|
||||
type AudioProvider interface {
|
||||
PlayBGM(song string)
|
||||
LoadSoundEffect(sfx string) (SoundEffect, error)
|
||||
LoadSound(sfx string, loop bool, bgm bool) (SoundEffect, error)
|
||||
SetVolumes(bgmVolume, sfxVolume float64)
|
||||
}
|
||||
|
@ -4,4 +4,6 @@ package d2interface
|
||||
type SoundEffect interface {
|
||||
Play()
|
||||
Stop()
|
||||
IsPlaying() bool
|
||||
SetVolume(volume float64)
|
||||
}
|
||||
|
@ -290,12 +290,12 @@ const (
|
||||
SFXButtonClick = "cursor_button_click"
|
||||
SFXAmazonDeselect = "cursor_amazon_deselect"
|
||||
SFXAmazonSelect = "cursor_amazon_select"
|
||||
SFXAssassinDeselect = "/data/global/sfx/Cursor/intro/assassin deselect.wav"
|
||||
SFXAssassinSelect = "/data/global/sfx/Cursor/intro/assassin select.wav"
|
||||
SFXAssassinDeselect = "Cursor/intro/assassin deselect.wav"
|
||||
SFXAssassinSelect = "Cursor/intro/assassin select.wav"
|
||||
SFXBarbarianDeselect = "cursor_barbarian_deselect"
|
||||
SFXBarbarianSelect = "cursor_barbarian_select"
|
||||
SFXDruidDeselect = "/data/global/sfx/Cursor/intro/druid deselect.wav"
|
||||
SFXDruidSelect = "/data/global/sfx/Cursor/intro/druid select.wav"
|
||||
SFXDruidDeselect = "Cursor/intro/druid deselect.wav"
|
||||
SFXDruidSelect = "Cursor/intro/druid select.wav"
|
||||
SFXNecromancerDeselect = "cursor_necromancer_deselect"
|
||||
SFXNecromancerSelect = "cursor_necromancer_select"
|
||||
SFXPaladinDeselect = "cursor_paladin_deselect"
|
||||
|
@ -85,7 +85,7 @@ func (d *DataDictionary) List(field string) []string {
|
||||
func (d *DataDictionary) Bool(field string) bool {
|
||||
n := d.Number(field)
|
||||
if n > 1 {
|
||||
log.Panic("Bool on non-bool field")
|
||||
log.Panic("Bool on non-bool field ", field)
|
||||
}
|
||||
|
||||
return n == 1
|
||||
|
@ -97,8 +97,12 @@ func (eap *AudioProvider) PlayBGM(song string) {
|
||||
}
|
||||
|
||||
// LoadSoundEffect loads a sound affect so that it canb e played
|
||||
func (eap *AudioProvider) LoadSoundEffect(sfx string) (d2interface.SoundEffect, error) {
|
||||
result := CreateSoundEffect(sfx, eap.audioContext, eap.sfxVolume) // TODO: Split
|
||||
func (eap *AudioProvider) LoadSound(sfx string, loop bool, bgm bool) (d2interface.SoundEffect, error) {
|
||||
volume := eap.sfxVolume
|
||||
if bgm {
|
||||
volume = eap.bgmVolume
|
||||
}
|
||||
result := CreateSoundEffect(sfx, eap.audioContext, volume, loop) // TODO: Split
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
@ -12,40 +12,53 @@ import (
|
||||
|
||||
// SoundEffect represents an ebiten implementation of a sound effect
|
||||
type SoundEffect struct {
|
||||
player *audio.Player
|
||||
player *audio.Player
|
||||
volumeScale float64
|
||||
}
|
||||
|
||||
// CreateSoundEffect creates a new instance of ebiten's sound effect implementation.
|
||||
func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *SoundEffect {
|
||||
func CreateSoundEffect(sfx string, context *audio.Context, volume float64, loop bool) *SoundEffect {
|
||||
result := &SoundEffect{}
|
||||
|
||||
var soundFile string
|
||||
soundFile := "/data/global/sfx/"
|
||||
|
||||
if _, exists := d2datadict.Sounds[sfx]; exists {
|
||||
soundEntry := d2datadict.Sounds[sfx]
|
||||
soundFile = soundEntry.FileName
|
||||
soundFile += soundEntry.FileName
|
||||
} else {
|
||||
soundFile = sfx
|
||||
soundFile += sfx
|
||||
}
|
||||
|
||||
audioData, err := d2asset.LoadFile(soundFile)
|
||||
audioData, err := d2asset.LoadFileStream(soundFile)
|
||||
|
||||
if err != nil {
|
||||
audioData, err = d2asset.LoadFileStream("/data/global/music/" + sfx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
d, err := wav.Decode(context, audio.BytesReadSeekCloser(audioData))
|
||||
d, err := wav.Decode(context, audioData)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
player, err := audio.NewPlayer(context, d)
|
||||
var player *audio.Player
|
||||
|
||||
if loop {
|
||||
s := audio.NewInfiniteLoop(d, d.Length())
|
||||
player, err = audio.NewPlayer(context, s)
|
||||
} else {
|
||||
player, err = audio.NewPlayer(context, d)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
result.volumeScale = volume
|
||||
player.SetVolume(volume)
|
||||
|
||||
result.player = player
|
||||
@ -53,6 +66,14 @@ func CreateSoundEffect(sfx string, context *audio.Context, volume float64) *Soun
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *SoundEffect) SetVolume(volume float64) {
|
||||
v.player.SetVolume(volume * v.volumeScale)
|
||||
}
|
||||
|
||||
func (v *SoundEffect) IsPlaying() bool {
|
||||
return v.player.IsPlaying()
|
||||
}
|
||||
|
||||
// Play plays the sound effect
|
||||
func (v *SoundEffect) Play() {
|
||||
err := v.player.Rewind()
|
||||
|
195
d2core/d2audio/sound_engine.go
Normal file
195
d2core/d2audio/sound_engine.go
Normal file
@ -0,0 +1,195 @@
|
||||
package d2audio
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
)
|
||||
|
||||
type envState int
|
||||
|
||||
const (
|
||||
envAttack = 0
|
||||
envSustain = 1
|
||||
envRelease = 2
|
||||
envStopped = 3
|
||||
)
|
||||
|
||||
const volMax float64 = 255
|
||||
const originalFPS float64 = 25
|
||||
|
||||
// A Sound that can be started and stopped
|
||||
type Sound struct {
|
||||
effect d2interface.SoundEffect
|
||||
entry *d2datadict.SoundEntry
|
||||
volume float64
|
||||
vTarget float64
|
||||
vRate float64
|
||||
state envState
|
||||
// panning float64 // lets forget about this for now
|
||||
}
|
||||
|
||||
func (s *Sound) update(elapsed float64) {
|
||||
// attack
|
||||
if s.state == envAttack {
|
||||
s.volume += s.vRate * elapsed
|
||||
if s.volume > s.vTarget {
|
||||
s.volume = s.vTarget
|
||||
s.state = envSustain
|
||||
}
|
||||
|
||||
s.effect.SetVolume(s.volume)
|
||||
}
|
||||
|
||||
// release
|
||||
if s.state == envRelease {
|
||||
s.volume -= s.vRate * elapsed
|
||||
if s.volume < 0 {
|
||||
s.effect.Stop()
|
||||
s.volume = 0
|
||||
s.state = envStopped
|
||||
}
|
||||
|
||||
s.effect.SetVolume(s.volume)
|
||||
}
|
||||
}
|
||||
|
||||
// Play the sound
|
||||
func (s *Sound) Play() {
|
||||
log.Println("starting sound", s.entry.Handle)
|
||||
s.effect.Play()
|
||||
|
||||
if s.entry.FadeIn != 0 {
|
||||
s.effect.SetVolume(0)
|
||||
s.volume = 0
|
||||
s.state = envAttack
|
||||
s.vTarget = float64(s.entry.Volume) / volMax
|
||||
s.vRate = (s.vTarget / (float64(s.entry.FadeIn) / originalFPS))
|
||||
} else {
|
||||
s.volume = float64(s.entry.Volume) / volMax
|
||||
s.effect.SetVolume(s.volume)
|
||||
s.state = envSustain
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the sound, only required for looping sounds
|
||||
func (s *Sound) Stop() {
|
||||
if s.entry.FadeOut != 0 {
|
||||
s.state = envRelease
|
||||
s.vTarget = 0
|
||||
s.vRate = (s.volume / (float64(s.entry.FadeOut) / originalFPS))
|
||||
} else {
|
||||
s.state = envStopped
|
||||
s.volume = 0
|
||||
s.effect.SetVolume(s.volume)
|
||||
s.effect.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
// SoundEngine provides functions for playing sounds
|
||||
type SoundEngine struct {
|
||||
provider d2interface.AudioProvider
|
||||
timer float64
|
||||
accTime float64
|
||||
sounds map[*Sound]struct{}
|
||||
}
|
||||
|
||||
// NewSoundEngine creates a new sound engine
|
||||
func NewSoundEngine(provider d2interface.AudioProvider, term d2interface.Terminal) *SoundEngine {
|
||||
r := SoundEngine{
|
||||
provider: provider,
|
||||
sounds: map[*Sound]struct{}{},
|
||||
timer: 1,
|
||||
}
|
||||
|
||||
_ = term.BindAction("playsoundid", "plays the sound for a given id", func(id int) {
|
||||
r.PlaySoundID(id)
|
||||
})
|
||||
|
||||
_ = term.BindAction("playsound", "plays the sound for a given handle string", func(handle string) {
|
||||
r.PlaySoundHandle(handle)
|
||||
})
|
||||
|
||||
_ = term.BindAction("activesounds", "list currently active sounds", func() {
|
||||
for s := range r.sounds {
|
||||
log.Println(s)
|
||||
}
|
||||
})
|
||||
|
||||
_ = term.BindAction("killsounds", "kill active sounds", func() {
|
||||
for s := range r.sounds {
|
||||
s.Stop()
|
||||
}
|
||||
})
|
||||
|
||||
return &r
|
||||
}
|
||||
|
||||
// Advance updates sound engine state, triggering events and envelopes
|
||||
func (s *SoundEngine) Advance(elapsed float64) {
|
||||
s.timer -= elapsed
|
||||
s.accTime += elapsed
|
||||
|
||||
if s.timer < 0 {
|
||||
for sound := range s.sounds {
|
||||
sound.update(s.accTime)
|
||||
|
||||
// Clean up finished non-looping effects
|
||||
if !sound.effect.IsPlaying() {
|
||||
delete(s.sounds, sound)
|
||||
}
|
||||
|
||||
// Clean up stopped looping effects
|
||||
if sound.state == envStopped {
|
||||
delete(s.sounds, sound)
|
||||
}
|
||||
}
|
||||
|
||||
s.timer = 0.2
|
||||
s.accTime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Reset stop all sounds and reset state
|
||||
func (s *SoundEngine) Reset() {
|
||||
for snd := range s.sounds {
|
||||
snd.effect.Stop()
|
||||
delete(s.sounds, snd)
|
||||
}
|
||||
}
|
||||
|
||||
// PlaySoundID plays a sound by sounds.txt index, returning the sound here is kinda ugly
|
||||
// now we could have a situation where someone holds onto the sound after the sound engine is done with it
|
||||
// someone needs to be in charge of deciding when to stopping looping sounds though...
|
||||
func (s *SoundEngine) PlaySoundID(id int) *Sound {
|
||||
if id == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
entry := d2datadict.SelectSoundByIndex(id)
|
||||
|
||||
if entry.GroupSize > 0 {
|
||||
entry = d2datadict.SelectSoundByIndex(entry.Index + rand.Intn(entry.GroupSize))
|
||||
}
|
||||
|
||||
effect, _ := s.provider.LoadSound(entry.FileName, entry.Loop, entry.MusicVol)
|
||||
|
||||
snd := Sound{
|
||||
entry: entry,
|
||||
effect: effect,
|
||||
}
|
||||
|
||||
s.sounds[&snd] = struct{}{}
|
||||
|
||||
snd.Play()
|
||||
|
||||
return &snd
|
||||
}
|
||||
|
||||
// PlaySoundHandle plays a sound by sounds.txt handle
|
||||
func (s *SoundEngine) PlaySoundHandle(handle string) *Sound {
|
||||
sound := d2datadict.Sounds[handle].Index
|
||||
return s.PlaySoundID(sound)
|
||||
}
|
55
d2core/d2audio/sound_environment.go
Normal file
55
d2core/d2audio/sound_environment.go
Normal file
@ -0,0 +1,55 @@
|
||||
package d2audio
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
)
|
||||
|
||||
type SoundEnvironment struct {
|
||||
environment *d2datadict.SoundEnvironRecord
|
||||
engine *SoundEngine
|
||||
bgm *Sound
|
||||
ambiance *Sound
|
||||
eventTimer float64
|
||||
}
|
||||
|
||||
func NewSoundEnvironment(soundEngine *SoundEngine) SoundEnvironment {
|
||||
r := SoundEnvironment{
|
||||
// Start with env NONE
|
||||
environment: d2datadict.SoundEnvirons[0],
|
||||
engine: soundEngine,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *SoundEnvironment) SetEnv(environment int) {
|
||||
if s.environment.Index != environment {
|
||||
newEnv := d2datadict.SoundEnvirons[environment]
|
||||
|
||||
if s.environment.Song != newEnv.Song {
|
||||
if s.bgm != nil {
|
||||
s.bgm.Stop()
|
||||
}
|
||||
|
||||
s.bgm = s.engine.PlaySoundID(newEnv.Song)
|
||||
}
|
||||
|
||||
if s.environment.DayAmbience != newEnv.DayAmbience {
|
||||
if s.ambiance != nil {
|
||||
s.ambiance.Stop()
|
||||
}
|
||||
|
||||
s.ambiance = s.engine.PlaySoundID(newEnv.DayAmbience)
|
||||
}
|
||||
|
||||
s.environment = newEnv
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SoundEnvironment) Advance(elapsed float64) {
|
||||
s.eventTimer -= elapsed
|
||||
if s.eventTimer < 0 {
|
||||
s.eventTimer = float64(s.environment.EventDelay) / 25
|
||||
s.engine.PlaySoundID(s.environment.DayEvent)
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ type UI struct {
|
||||
var singleton UI
|
||||
|
||||
func Initialize(inputManager d2interface.InputManager, audioProvider d2interface.AudioProvider) {
|
||||
sfx, err := audioProvider.LoadSoundEffect(d2resource.SFXButtonClick)
|
||||
sfx, err := audioProvider.LoadSound(d2resource.SFXButtonClick, false, false)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to initialize ui: %v", err)
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) onLoad() {
|
||||
m.selectSound, _ = m.audioProvider.LoadSoundEffect(d2resource.SFXCursorSelect)
|
||||
m.selectSound, _ = m.audioProvider.LoadSound(d2resource.SFXCursorSelect, false, false)
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) onEscKey() {
|
||||
|
@ -2,14 +2,13 @@ package d2gamescreen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
@ -36,6 +35,8 @@ type Game struct {
|
||||
lastRegionType d2enum.RegionIdType
|
||||
ticksSinceLevelCheck float64
|
||||
escapeMenu *EscapeMenu
|
||||
soundEngine *d2audio.SoundEngine
|
||||
soundEnv d2audio.SoundEnvironment
|
||||
|
||||
renderer d2interface.Renderer
|
||||
inputManager d2interface.InputManager
|
||||
@ -75,7 +76,10 @@ func CreateGame(
|
||||
audioProvider: audioProvider,
|
||||
renderer: renderer,
|
||||
terminal: term,
|
||||
soundEngine: d2audio.NewSoundEngine(audioProvider, term),
|
||||
}
|
||||
result.soundEnv = d2audio.NewSoundEnvironment(result.soundEngine)
|
||||
|
||||
result.escapeMenu.onLoad()
|
||||
|
||||
if err := inputManager.BindHandler(result.escapeMenu); err != nil {
|
||||
@ -125,6 +129,8 @@ func (v *Game) OnUnload() error {
|
||||
return err
|
||||
}
|
||||
|
||||
v.soundEngine.Reset()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -152,6 +158,8 @@ func (v *Game) Render(screen d2interface.Surface) error {
|
||||
|
||||
// Advance runs the update logic on the Gameplay screen
|
||||
func (v *Game) Advance(elapsed float64) error {
|
||||
v.soundEngine.Advance(elapsed)
|
||||
|
||||
if (v.escapeMenu != nil && !v.escapeMenu.isOpen) || len(v.gameClient.Players) != 1 {
|
||||
v.gameClient.MapEngine.Advance(elapsed) // TODO: Hack
|
||||
}
|
||||
@ -170,8 +178,7 @@ func (v *Game) Advance(elapsed float64) error {
|
||||
tile := v.gameClient.MapEngine.TileAt(int(tilePosition.X()), int(tilePosition.Y()))
|
||||
|
||||
if tile != nil {
|
||||
musicInfo := d2common.GetMusicDef(tile.RegionType)
|
||||
v.audioProvider.PlayBGM(musicInfo.MusicFile)
|
||||
v.soundEnv.SetEnv(d2datadict.LevelDetails[int(tile.RegionType)].SoundEnvironmentID)
|
||||
|
||||
// skip showing zone change text the first time we enter the world
|
||||
if v.lastRegionType != d2enum.RegionNone && v.lastRegionType != tile.RegionType {
|
||||
@ -203,6 +210,8 @@ func (v *Game) Advance(elapsed float64) error {
|
||||
v.mapRenderer.SetCameraTarget(&position)
|
||||
}
|
||||
|
||||
v.soundEnv.Advance(elapsed)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -755,6 +755,6 @@ func loadSprite(animationPath string, position image.Point, playLength int, play
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) loadSoundEffect(sfx string) d2interface.SoundEffect {
|
||||
result, _ := v.audioProvider.LoadSoundEffect(sfx)
|
||||
result, _ := v.audioProvider.LoadSound(sfx, false, false)
|
||||
return result
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user