Compare commits

...

3 Commits

Author SHA1 Message Date
fd73f03aa5 Initial outline of a Ship 2020-04-02 01:23:04 +01:00
df1f116b3d Clean up the options flow handlers a tiny bit 2020-04-02 01:22:53 +01:00
aa43011e8d Set options from defaults on first start
Data/GenericData.dat specifies what the default values for some options
should be. Respect them on startup if the options in config are unset.
2020-04-02 01:21:32 +01:00
6 changed files with 182 additions and 21 deletions

View File

@@ -35,6 +35,7 @@ type AssetStore struct {
// These members are used to store things we've already loaded
fonts map[string]*Font
generic *data.Generic
maps map[string]*Map
menus map[string]*Menu
objs map[string]*Object

View File

@@ -0,0 +1,62 @@
package assetstore
import (
"code.ur.gs/lupine/ordoor/internal/config"
"code.ur.gs/lupine/ordoor/internal/data"
)
// Generic returns a struct containing a grab-bag of otherwise-unrelated data
// TODO: it would be nice if this could be cleaner
func (a *AssetStore) Generic() (*data.Generic, error) {
if a.generic != nil {
return a.generic, nil
}
filename, err := a.lookup("GenericData", "dat", "Data")
if err != nil {
return nil, err
}
generic, err := data.LoadGeneric(filename)
if err != nil {
return nil, err
}
a.generic = generic
return generic, nil
}
func (a *AssetStore) DefaultOptions() (*config.Options, error) {
cfg := &config.Options{}
g, err := a.Generic()
if err != nil {
return nil, err
}
cfg.PlayMovies = intToBool(g.Options[data.OptionMovies])
cfg.PlayMusic = intToBool(g.Options[data.OptionMusic])
cfg.CombatVoices = intToBool(g.Options[data.OptionCombatVoices])
cfg.ShowGrid = intToBool(g.Options[data.OptionGrid])
cfg.ShowPaths = intToBool(g.Options[data.OptionShowPaths])
cfg.PointSaving = intToBool(g.Options[data.OptionPointSave])
cfg.AutoCutLevel = intToBool(g.Options[data.OptionAutoCutLevel])
cfg.Animations = intToBool(g.Options[data.OptionShowUnitAnimations])
// These are overrides of data.OptionCombatResolution. *This* default from
// 1998 is no good at all!
cfg.XRes = 1280
cfg.YRes = 1024
cfg.MusicVolume = g.Options[data.OptionMusicVolume]
cfg.SFXVolume = g.Options[data.OptionSoundEffectsVolume]
cfg.UnitSpeed = g.Options[data.OptionUnitAnimationSpeed]
cfg.AnimSpeed = g.Options[data.OptionEffectAnimationSpeed]
return cfg, nil
}
func intToBool(i int) bool {
return i > 0
}

View File

@@ -1,6 +1,7 @@
package config
import (
"errors"
"os"
"path/filepath"
@@ -37,8 +38,9 @@ type Options struct {
type Config struct {
filename string `toml:"-"`
Ordoor `toml:"ordoor"`
Options `toml:"options"`
Defaults *Options `toml:"-"`
Ordoor `toml:"ordoor"`
Options `toml:"options"`
}
func Load(filename string) (*Config, error) {
@@ -54,6 +56,12 @@ func Load(filename string) (*Config, error) {
return &out, err
}
func (c *Config) HasUnsetOptions() bool {
var empty Options
return c.Options == empty
}
func (c *Config) Save() error {
f, err := os.OpenFile(c.filename, os.O_WRONLY, 0644)
if err != nil {
@@ -69,6 +77,16 @@ func (c *Config) DataFile(path string) string {
return filepath.Join(c.DataDir, path)
}
func (c *Config) ResetDefaults() error {
if c.Defaults == nil {
return errors.New("Defaults not available")
}
c.Options = *c.Defaults
return c.Save()
}
func (o *Options) ResolutionIndex() int {
if o.XRes == 640 && o.YRes == 480 {
return 1

View File

@@ -11,8 +11,8 @@ func (f *Flow) linkOptions() {
f.configureSlider(options, "2.10", v10Slider) // Music volume slider
f.configureSlider(options, "2.11", v10Slider) // SFX volume slider
f.onClick(options, "2.12", f.acceptOptions()) // OK button
f.onClick(options, "2.24", f.cancelOptions()) // Cancel button
f.onClick(options, "2.12", f.acceptOptions) // OK button
f.onClick(options, "2.24", f.cancelOptions) // Cancel button
f.configureSlider(options, "2.26", h9Slider) // Unit speed slider
f.configureSlider(options, "2.27", h9Slider) // Animation speed slider
@@ -21,31 +21,27 @@ func (f *Flow) linkOptions() {
// TODO: implement keybindings save/load behaviour
f.onClick(kbd, "3.1", f.setDriver(options)) // Done button
f.onClick(kbd, "3.2", f.setDriver(options)) // Cancel button
f.onClick(kbd, "3.4", func() {}) // Reset to defaults button
f.onClick(kbd, "3.4", func() {}) // TODO: Reset to defaults button
}
// FIXME: exiting is a bit OTT. Perhaps display "save failed"?
func (f *Flow) acceptOptions() func() {
return func() {
if err := f.optionsIntoConfig(); err != nil {
log.Printf("Saving options to config failed: %v", err)
f.exit = err
} else {
f.setDriverNow(main)
}
func (f *Flow) acceptOptions() {
if err := f.optionsIntoConfig(); err != nil {
log.Printf("Saving options to config failed: %v", err)
f.exit = err
} else {
f.setDriverNow(main)
}
}
// FIXME: again, exiting is OTT. We're just resetting the state of
// the interface to the values in config.
func (f *Flow) cancelOptions() func() {
return func() {
if err := f.configIntoOptions(); err != nil {
log.Printf("Saving options to config failed: %v", err)
f.exit = err
} else {
f.exit = f.returnToLastDriverNow(options)
}
func (f *Flow) cancelOptions() {
if err := f.configIntoOptions(); err != nil {
log.Printf("Saving options to config failed: %v", err)
f.exit = err
} else {
f.exit = f.returnToLastDriverNow(options)
}
}

View File

@@ -35,6 +35,8 @@ type Ordoor struct {
music *audio.Player
win *ui.Window
ship *Ship
state gameState
nextState gameState
@@ -53,6 +55,18 @@ func Run(configFile string, overrideX, overrideY int) error {
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)
}

70
internal/ordoor/ship.go Normal file
View File

@@ -0,0 +1,70 @@
package ordoor
// Ship encapsulates campaign state, including current location in the campaign,
// marines and their stats, supplies, etc.
type Ship struct {
CurrentMission string
Squads []*Squad
Captain *Character
Chaplain *Character
Apothecary *Character
Techmarines [2]*Character
Librarians [4]*Character
}
type SquadType int
type CharacterType int
const (
SquadTypeTactical SquadType = 0
SquadTypeTerminator SquadType = 1
SquadTypeAssault SquadType = 2
SquadTypeDevastator SquadType = 3
CharTypeMarine CharacterType = 0
CharTypeCaptain CharacterType = 1
CharTypeChaplain CharacterType = 2
CharTypeApothecary CharacterType = 3
CharTypeTechmarine CharacterType = 4
CharTypeLibrarian CharacterType = 5
)
type Squad struct {
Type SquadType
Characters []*Character
}
type Character struct {
Name string
Type CharacterType
Stats
Honours
}
type Stats struct {
ActionPoints int
Health int
Armour int
BallisticSkill int
WeaponSkill int
Strength int
Toughness int
Initiative int
Attacks int
Leadership int
MissionCount int
KillCount int
Experience int
}
type Honours struct {
Marksman bool
CruxTerminatus bool
PuritySeal bool
ImperialLaurel bool
}