Remiplement Add to use reflection.
Now it matters whether `FieldLabel`s are spelled correctly, but in return, we don't have to write and maintain that obnoxious `switch` statement.
This commit is contained in:
parent
8a28f38d4d
commit
2d16f97314
@ -9,7 +9,6 @@ import (
|
||||
var (
|
||||
ErrOptionNotEnabled = errors.New("option not enabled")
|
||||
ErrPolicyNotEnacted = errors.New("cannot unenact policy that is not enacted")
|
||||
ErrNoFieldLabel = errors.New("field does not exist")
|
||||
|
||||
// ErrUnimplemented and ErrKeepMessaage are "non-errors". They are used
|
||||
// as special signals that the result needs to be handled in a special way;
|
||||
|
@ -1,7 +1,9 @@
|
||||
package koboldsim
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
||||
)
|
||||
@ -167,6 +169,10 @@ func NewKoboldMine() *KoboldMine {
|
||||
}
|
||||
}
|
||||
|
||||
// FieldLabel instances are strings exactly matching the name of an
|
||||
// exported field in `KoboldMine`. These are used to map field names to
|
||||
// amounts to change in `TablePolicy` instances, which are then looked
|
||||
// up by name (via reflection) when adding the stat.
|
||||
type FieldLabel string
|
||||
|
||||
const (
|
||||
@ -188,56 +194,51 @@ const (
|
||||
Secrecy FieldLabel = "Secrecy"
|
||||
)
|
||||
|
||||
func (k *KoboldMine) Add(which FieldLabel, amount float64) error {
|
||||
switch which {
|
||||
case Authoritarianism:
|
||||
k.Authoritarianism += amount
|
||||
return nil
|
||||
case BasePopulation:
|
||||
k.BasePopulation += amount
|
||||
return nil
|
||||
case Bureaucracy:
|
||||
k.Bureaucracy += amount
|
||||
return nil
|
||||
case Construction:
|
||||
k.Construction += amount
|
||||
return nil
|
||||
case Cruelty:
|
||||
k.Cruelty += amount
|
||||
return nil
|
||||
case Education:
|
||||
k.Education += amount
|
||||
return nil
|
||||
case FoodSupply:
|
||||
k.FoodSupply += amount
|
||||
return nil
|
||||
case ForeignRelations:
|
||||
k.ForeignRelations += amount
|
||||
return nil
|
||||
case Gullibility:
|
||||
k.Gullibility += amount
|
||||
return nil
|
||||
case Madness:
|
||||
k.Madness += amount
|
||||
return nil
|
||||
case Manufacturing:
|
||||
k.Manufacturing += amount
|
||||
return nil
|
||||
case Mining:
|
||||
k.Mining += amount
|
||||
return nil
|
||||
case Militarism:
|
||||
k.Militarism += amount
|
||||
return nil
|
||||
case Rebellion:
|
||||
k.Rebellion += amount
|
||||
return nil
|
||||
case Scavenging:
|
||||
k.Scavenging += amount
|
||||
return nil
|
||||
case Secrecy:
|
||||
k.Secrecy += amount
|
||||
// ErrBadFieldLabel is an "error category" for all errors where a
|
||||
// FieldLabel did not correctly name a Field that could be used in Add.
|
||||
var ErrBadFieldLabel = errors.New("bad field label")
|
||||
|
||||
// ErrNoFieldLabel is a kind of `ErrBadFieldLabel` used when no field
|
||||
// of the target has the exact name specified in the FieldLabel. Check
|
||||
// spelling and capitalization.
|
||||
var ErrNoFieldLabel = fmt.Errorf("%w: field does not exist", ErrBadFieldLabel)
|
||||
|
||||
// ErrFieldNotFloat is a kind of `ErrBadFieldLabel` used when it is not
|
||||
// possible to read and assign a float to the named field. Is this the
|
||||
// name of a calculated stat (a function) rather than a base stat?
|
||||
var ErrFieldNotFloat = fmt.Errorf("%w: field type is not float", ErrBadFieldLabel)
|
||||
|
||||
// ErrFieldSetPanic is a kind of `ErrBadFieldLabel` used when trying to
|
||||
// set the value of a field panicked. The panic message should be
|
||||
// preserved in the error to diagnose the problem. If the problem is
|
||||
// that the field is unexported, capitalize the name (including inside
|
||||
// the KoboldMine type). Any other issue is a more complicated bug,
|
||||
// because all of them that aren't already caught by ErrFieldNotFloat
|
||||
// imply something very unexpected happened with `k` itself (in `Add`).
|
||||
var ErrFieldSetPanic = fmt.Errorf("%w: panic when setting", ErrBadFieldLabel)
|
||||
|
||||
// Use a FieldLabel to add an amount to the matching field. If no such
|
||||
// field can be found, the field is not exported, or the field is not
|
||||
// of type float64, this returns an error ad does not change any values.
|
||||
func (k *KoboldMine) Add(which FieldLabel, amount float64) (finalErr error) {
|
||||
kv := reflect.ValueOf(k).Elem()
|
||||
f := kv.FieldByName(string(which))
|
||||
if !f.IsValid() {
|
||||
return fmt.Errorf("cannot add %f to field %q: %w", amount, which, ErrNoFieldLabel)
|
||||
}
|
||||
if !f.CanFloat() {
|
||||
return fmt.Errorf("cannot add %f to field %q: %w", amount, which, ErrFieldNotFloat)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(error); ok {
|
||||
finalErr = fmt.Errorf("could not add %f to field %q: %w: %w", amount, which, ErrFieldSetPanic, e)
|
||||
} else {
|
||||
finalErr = fmt.Errorf("could not add %f to field %q: %w: %v", amount, which, ErrFieldSetPanic, r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
f.SetFloat(f.Float() + amount)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cannot add %f to %q: %w", amount, which, ErrNoFieldLabel)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user