273 lines
8.7 KiB
Go
273 lines
8.7 KiB
Go
package edit
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/inkyblackness/hacked/ss1/content/archive"
|
|
"github.com/inkyblackness/hacked/ss1/edit/undoable/cmd"
|
|
"github.com/inkyblackness/hacked/ss1/world"
|
|
"github.com/inkyblackness/hacked/ss1/world/citadel"
|
|
)
|
|
|
|
// VariableBaseContextIdentifier identifies which context for variable naming should be used.
|
|
type VariableBaseContextIdentifier int
|
|
|
|
// Context identifier are listed below.
|
|
const (
|
|
VariableContextCitadel = VariableBaseContextIdentifier(0)
|
|
VariableContextEngine = VariableBaseContextIdentifier(1)
|
|
)
|
|
|
|
// VariableContextIdentifiers returns a list of all available identifiers.
|
|
func VariableContextIdentifiers() []VariableBaseContextIdentifier {
|
|
return []VariableBaseContextIdentifier{VariableContextCitadel, VariableContextEngine}
|
|
}
|
|
|
|
// GameStateSettings describe the game state details.
|
|
type GameStateSettings struct {
|
|
BaseContext int
|
|
|
|
BooleanVariables []VariableSettings
|
|
IntegerVariables []VariableSettings
|
|
}
|
|
|
|
// VariableSettings describe game variables.
|
|
type VariableSettings struct {
|
|
Index int
|
|
|
|
ResetValue *int16 `json:",omitempty"`
|
|
Name string
|
|
Description string
|
|
Limits *struct {
|
|
Minimum int16
|
|
Maximum int16
|
|
} `json:",omitempty"`
|
|
ValueNames []struct {
|
|
Value int16
|
|
Name string
|
|
} `json:",omitempty"`
|
|
}
|
|
|
|
func variableSettingsFrom(variables archive.GameVariables) []VariableSettings {
|
|
settings := make([]VariableSettings, 0, len(variables))
|
|
for varIndex, varInfo := range variables {
|
|
varSettings := VariableSettings{
|
|
Index: varIndex,
|
|
ResetValue: varInfo.InitValue,
|
|
Name: varInfo.Name,
|
|
Description: varInfo.Description,
|
|
Limits: nil,
|
|
ValueNames: nil,
|
|
}
|
|
if varInfo.Limits != nil {
|
|
varSettings.Limits = &struct {
|
|
Minimum int16
|
|
Maximum int16
|
|
}{
|
|
Minimum: varInfo.Limits.Minimum,
|
|
Maximum: varInfo.Limits.Maximum,
|
|
}
|
|
}
|
|
for valIndex, valName := range varInfo.ValueNames {
|
|
varSettings.ValueNames = append(varSettings.ValueNames,
|
|
struct {
|
|
Value int16
|
|
Name string
|
|
}{
|
|
Value: valIndex,
|
|
Name: valName,
|
|
})
|
|
}
|
|
settings = append(settings, varSettings)
|
|
}
|
|
return settings
|
|
}
|
|
|
|
func variablesFrom(list []VariableSettings) archive.GameVariables {
|
|
variables := make(archive.GameVariables)
|
|
for _, settings := range list {
|
|
varInfo := archive.GameVariableInfo{
|
|
InitValue: settings.ResetValue,
|
|
Name: settings.Name,
|
|
Description: settings.Description,
|
|
}
|
|
if settings.Limits != nil {
|
|
varInfo.Limits = &archive.GameVariableLimits{
|
|
Minimum: settings.Limits.Maximum,
|
|
Maximum: settings.Limits.Minimum,
|
|
}
|
|
}
|
|
if len(settings.ValueNames) > 0 {
|
|
varInfo.ValueNames = make(map[int16]string)
|
|
for _, valName := range settings.ValueNames {
|
|
varInfo.ValueNames[valName.Value] = valName.Name
|
|
}
|
|
}
|
|
variables[settings.Index] = varInfo
|
|
}
|
|
return variables
|
|
}
|
|
|
|
// GameStateService handles all details on the global game state.
|
|
type GameStateService struct {
|
|
registry cmd.Registry
|
|
|
|
currentContext VariableBaseContextIdentifier
|
|
|
|
booleanVariables archive.GameVariables
|
|
integerVariables archive.GameVariables
|
|
}
|
|
|
|
// NewGameStateService returns a new instance.
|
|
func NewGameStateService(registry cmd.Registry) *GameStateService {
|
|
return &GameStateService{
|
|
registry: registry,
|
|
|
|
currentContext: VariableContextCitadel,
|
|
|
|
booleanVariables: make(archive.GameVariables),
|
|
integerVariables: make(archive.GameVariables),
|
|
}
|
|
}
|
|
|
|
// CurrentSettings returns the snapshot of the project.
|
|
func (service GameStateService) CurrentSettings() GameStateSettings {
|
|
return GameStateSettings{
|
|
BaseContext: int(service.currentContext),
|
|
BooleanVariables: variableSettingsFrom(service.booleanVariables),
|
|
IntegerVariables: variableSettingsFrom(service.integerVariables),
|
|
}
|
|
}
|
|
|
|
// RestoreSettings loads the given snapshot.
|
|
func (service *GameStateService) RestoreSettings(settings GameStateSettings) {
|
|
service.currentContext = VariableBaseContextIdentifier(settings.BaseContext)
|
|
service.booleanVariables = variablesFrom(settings.BooleanVariables)
|
|
service.integerVariables = variablesFrom(settings.IntegerVariables)
|
|
}
|
|
|
|
// VariableBaseContext returns the current context to use as basis for variables not specified by the project.
|
|
func (service GameStateService) VariableBaseContext() VariableBaseContextIdentifier {
|
|
return service.currentContext
|
|
}
|
|
|
|
// SetVariableBaseContext sets the current context to use as basis for variables not specified by the project.
|
|
func (service *GameStateService) SetVariableBaseContext(identifier VariableBaseContextIdentifier) {
|
|
service.currentContext = identifier
|
|
}
|
|
|
|
func (service GameStateService) baseInfoProvider() archive.GameVariableInfoProvider {
|
|
switch service.currentContext {
|
|
case VariableContextCitadel:
|
|
return citadel.MissionVariables{}
|
|
case VariableContextEngine:
|
|
return archive.EngineVariables{}
|
|
default:
|
|
panic(fmt.Sprintf("invalid identifier: %d", service.currentContext))
|
|
}
|
|
}
|
|
|
|
// DefaultAllVariables removes all project specific overrides.
|
|
func (service *GameStateService) DefaultAllVariables() error {
|
|
return service.registry.Register(cmd.Named("RemoveAllOverrides"),
|
|
cmd.Nested(func() error {
|
|
for i := 0; i < archive.BooleanVarCount; i++ {
|
|
err := service.DefaultBooleanVariable(i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for i := 0; i < archive.IntegerVarCount; i++ {
|
|
err := service.DefaultIntegerVariable(i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}))
|
|
}
|
|
|
|
// IntegerVariableOverride returns true if project-specific details are stored for given variable index.
|
|
func (service GameStateService) IntegerVariableOverride(index int) bool {
|
|
_, perProject := service.integerVariables[index]
|
|
return perProject
|
|
}
|
|
|
|
// IntegerVariable returns the variable info as per project settings for the given index.
|
|
func (service GameStateService) IntegerVariable(index int) archive.GameVariableInfo {
|
|
baseInfo := service.baseInfoProvider().IntegerVariable(index)
|
|
projInfo, perProject := service.integerVariables[index]
|
|
if perProject {
|
|
projInfo.Hardcoded = baseInfo.Hardcoded
|
|
return projInfo
|
|
}
|
|
return baseInfo
|
|
}
|
|
|
|
// SetIntegerVariable sets the variable info for the given index in the project settings.
|
|
func (service *GameStateService) SetIntegerVariable(index int, info archive.GameVariableInfo) error {
|
|
return service.registry.Register(cmd.Named("SetIntegerVariable"),
|
|
cmd.Forward(setVariableTask(service.integerVariables, index, info)),
|
|
cmd.Reverse(restoreVariableTask(service.integerVariables, index)))
|
|
}
|
|
|
|
// DefaultIntegerVariable clears the variable info for the given index in the project settings.
|
|
func (service *GameStateService) DefaultIntegerVariable(index int) error {
|
|
return service.registry.Register(cmd.Named("DefaultIntegerVariable"),
|
|
cmd.Forward(deleteVariableTask(service.integerVariables, index)),
|
|
cmd.Reverse(restoreVariableTask(service.integerVariables, index)))
|
|
}
|
|
|
|
// BooleanVariableOverride returns true if project-specific details are stored for given variable index.
|
|
func (service GameStateService) BooleanVariableOverride(index int) bool {
|
|
_, perProject := service.booleanVariables[index]
|
|
return perProject
|
|
}
|
|
|
|
// BooleanVariable returns the variable info as per project settings for the given index.
|
|
func (service GameStateService) BooleanVariable(index int) archive.GameVariableInfo {
|
|
baseInfo := service.baseInfoProvider().BooleanVariable(index)
|
|
projInfo, perProject := service.booleanVariables[index]
|
|
if perProject {
|
|
projInfo.Hardcoded = baseInfo.Hardcoded
|
|
return projInfo
|
|
}
|
|
return baseInfo
|
|
}
|
|
|
|
// SetBooleanVariable sets the variable info for the given index in the project settings.
|
|
func (service *GameStateService) SetBooleanVariable(index int, info archive.GameVariableInfo) error {
|
|
return service.registry.Register(cmd.Named("SetBooleanVariable"),
|
|
cmd.Forward(setVariableTask(service.booleanVariables, index, info)),
|
|
cmd.Reverse(restoreVariableTask(service.booleanVariables, index)))
|
|
}
|
|
|
|
// DefaultBooleanVariable clears the variable info for the given index in the project settings.
|
|
func (service *GameStateService) DefaultBooleanVariable(index int) error {
|
|
return service.registry.Register(cmd.Named("DefaultBooleanVariable"),
|
|
cmd.Forward(deleteVariableTask(service.booleanVariables, index)),
|
|
cmd.Reverse(restoreVariableTask(service.booleanVariables, index)))
|
|
}
|
|
|
|
func setVariableTask(variables archive.GameVariables, index int, info archive.GameVariableInfo) cmd.Task {
|
|
return func(modder world.Modder) error {
|
|
variables[index] = info
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func deleteVariableTask(variables archive.GameVariables, index int) cmd.Task {
|
|
return func(modder world.Modder) error {
|
|
delete(variables, index)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func restoreVariableTask(variables archive.GameVariables, index int) cmd.Task {
|
|
info, present := variables[index]
|
|
if present {
|
|
return setVariableTask(variables, index, info)
|
|
}
|
|
return deleteVariableTask(variables, index)
|
|
}
|