174 lines
3.7 KiB
Go
174 lines
3.7 KiB
Go
// package ordoor implements the full WH40K.EXE functionality, and is used from
|
|
// cmd/ordoor/main.go
|
|
//
|
|
// Entrypoint is Run()
|
|
package ordoor
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
"github.com/hajimehoshi/ebiten/audio"
|
|
|
|
"code.ur.gs/lupine/ordoor/internal/assetstore"
|
|
"code.ur.gs/lupine/ordoor/internal/config"
|
|
"code.ur.gs/lupine/ordoor/internal/flow"
|
|
"code.ur.gs/lupine/ordoor/internal/ship"
|
|
"code.ur.gs/lupine/ordoor/internal/ui"
|
|
)
|
|
|
|
type gameState int
|
|
|
|
type Ordoor struct {
|
|
assets *assetstore.AssetStore
|
|
config *config.Config
|
|
music *audio.Player
|
|
win *ui.Window
|
|
|
|
// Relevant to interface state
|
|
flow *flow.Flow
|
|
|
|
// Relevant to campaign state
|
|
ship *ship.Ship
|
|
}
|
|
|
|
func Run(configFile string, overrideX, overrideY int) error {
|
|
cfg, err := config.Load(configFile, "ordoor")
|
|
if err != nil {
|
|
return fmt.Errorf("Couldn't load config file: %v", err)
|
|
}
|
|
|
|
assets, err := assetstore.New(cfg.DefaultEngine())
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to initialize asset store: %v", err)
|
|
}
|
|
|
|
defaults, err := assets.DefaultOptions()
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to read option defaults: %v", err)
|
|
}
|
|
|
|
cfg.Defaults = defaults
|
|
if cfg.HasUnsetOptions() {
|
|
if err := cfg.ResetDefaults(); err != nil {
|
|
return fmt.Errorf("Failed to set options on first-start: %v", err)
|
|
}
|
|
}
|
|
|
|
if _, err := audio.NewContext(48000); err != nil {
|
|
return fmt.Errorf("Failed to set up audio context: %v", err)
|
|
}
|
|
|
|
ordoor := &Ordoor{
|
|
assets: assets,
|
|
config: cfg,
|
|
ship: ship.New(),
|
|
}
|
|
|
|
x, y := cfg.Options.XRes, cfg.Options.YRes
|
|
if overrideX > 0 {
|
|
x = overrideX
|
|
}
|
|
if overrideY > 0 {
|
|
y = overrideY
|
|
}
|
|
|
|
win, err := ui.NewWindow(ordoor, "Ordoor", x, y)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create window: %v", err)
|
|
}
|
|
|
|
ordoor.win = win
|
|
|
|
if err := ordoor.setupFlow(); err != nil {
|
|
return fmt.Errorf("failed to setup UI flow: %v", err)
|
|
}
|
|
|
|
if err := ordoor.Run(); err != nil {
|
|
return fmt.Errorf("Run finished with error: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (o *Ordoor) Run() error {
|
|
// FIXME: we're missing a screen about SSI here
|
|
if o.config.Options.PlayMovies {
|
|
o.PlaySkippableVideo("LOGOS")
|
|
o.PlaySkippableVideo("movie1")
|
|
}
|
|
|
|
err := o.win.Run()
|
|
if err == flow.ErrExit {
|
|
log.Printf("Exit requested")
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// Only one music track can play at a time. This is handled at the toplevel.
|
|
// FIXME: should take references from Sounds.dat
|
|
// FIXME: music probably properly belongs to flow. This package can just do
|
|
// initialization and wire the flow to the ship?
|
|
func (o *Ordoor) PlayMusic(name string) error {
|
|
if o.music != nil {
|
|
if err := o.music.Close(); err != nil {
|
|
return fmt.Errorf("Failed to close old music: %v", err)
|
|
}
|
|
}
|
|
|
|
sound, err := o.assets.Sound(name)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to find sound %v: %v", name, err)
|
|
}
|
|
|
|
player, err := sound.InfinitePlayer()
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to generate music player for %v: %v", name, err)
|
|
}
|
|
o.music = player
|
|
|
|
if o.config.Options.PlayMusic {
|
|
player.Play()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (o *Ordoor) setupFlow() error {
|
|
o.PlayMusic("music_interface")
|
|
|
|
flow, err := flow.New(o.assets, o.config, o.ship)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
o.flow = flow
|
|
|
|
return nil
|
|
}
|
|
|
|
func (o *Ordoor) Update(screenX, screenY int) error {
|
|
// Ensure music is doing the right thing
|
|
if o.music != nil && o.music.IsPlaying() != o.config.Options.PlayMusic {
|
|
if o.config.Options.PlayMusic {
|
|
o.music.Rewind()
|
|
o.music.Play()
|
|
} else {
|
|
o.music.Pause()
|
|
}
|
|
}
|
|
|
|
return o.flow.Update(screenX, screenY)
|
|
}
|
|
|
|
func (o *Ordoor) Draw(screen *ebiten.Image) error {
|
|
return o.flow.Draw(screen)
|
|
}
|
|
|
|
func (o *Ordoor) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) {
|
|
return o.flow.Cursor()
|
|
}
|