Compare commits
5 Commits
39e4c94b6f
...
37d3b639bf
Author | SHA1 | Date | |
---|---|---|---|
37d3b639bf | |||
a237fa81bf | |||
68cab7d2be | |||
2d16f97314 | |||
8a28f38d4d |
9
.vscode/koboldsimsnippets.code-snippets
vendored
9
.vscode/koboldsimsnippets.code-snippets
vendored
@ -15,13 +15,4 @@
|
|||||||
// ],
|
// ],
|
||||||
// "description": "Log output to console"
|
// "description": "Log output to console"
|
||||||
// }
|
// }
|
||||||
"KoboldMine Add case": {
|
|
||||||
"scope": "go",
|
|
||||||
"prefix": "case",
|
|
||||||
"body": [
|
|
||||||
"case ${1:field}:",
|
|
||||||
"\tk.${1:field} += amount",
|
|
||||||
"\treturn nil",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -9,7 +9,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
ErrOptionNotEnabled = errors.New("option not enabled")
|
ErrOptionNotEnabled = errors.New("option not enabled")
|
||||||
ErrPolicyNotEnacted = errors.New("cannot unenact policy that is not enacted")
|
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
|
// ErrUnimplemented and ErrKeepMessaage are "non-errors". They are used
|
||||||
// as special signals that the result needs to be handled in a special way;
|
// as special signals that the result needs to be handled in a special way;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package koboldsim
|
package koboldsim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
"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
|
type FieldLabel string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -199,89 +205,44 @@ const (
|
|||||||
Welfare FieldLabel = "Welfare"
|
Welfare FieldLabel = "Welfare"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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) error {
|
func (k *KoboldMine) Add(which FieldLabel, amount float64) error {
|
||||||
switch which {
|
kv := reflect.ValueOf(k).Elem()
|
||||||
case Alchemy:
|
f := kv.FieldByName(string(which))
|
||||||
k.Alchemy += amount
|
if !f.IsValid() {
|
||||||
return nil
|
return fmt.Errorf("cannot add %f to field %q: %w", amount, which, ErrNoFieldLabel)
|
||||||
case Authoritarianism:
|
}
|
||||||
k.Authoritarianism += amount
|
if !f.CanFloat() {
|
||||||
return nil
|
return fmt.Errorf("cannot add %f to field %q: %w", amount, which, ErrFieldNotFloat)
|
||||||
case BasePopulation:
|
}
|
||||||
k.BasePopulation += amount
|
|
||||||
return nil
|
if err := try(func() { f.SetFloat(f.Float() + amount) }); err != nil {
|
||||||
case Bureaucracy:
|
return fmt.Errorf("could not add %f to field %q: %w", amount, which, err)
|
||||||
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 ForeignRelExpense:
|
|
||||||
k.ForeignRelExpense += amount
|
|
||||||
return nil
|
|
||||||
case Gadgetry:
|
|
||||||
k.Gadgetry += amount
|
|
||||||
return nil
|
|
||||||
case Greed:
|
|
||||||
k.Greed += amount
|
|
||||||
return nil
|
|
||||||
case Gullibility:
|
|
||||||
k.Gullibility += amount
|
|
||||||
return nil
|
|
||||||
case Healthcare:
|
|
||||||
k.Healthcare += amount
|
|
||||||
return nil
|
|
||||||
case HiddenRelPenalty:
|
|
||||||
k.HiddenRelPenalty += amount
|
|
||||||
return nil
|
|
||||||
case Hospitality:
|
|
||||||
k.Hospitality += amount
|
|
||||||
return nil
|
|
||||||
case Logistics:
|
|
||||||
k.Logistics += amount
|
|
||||||
return nil
|
|
||||||
case Madness:
|
|
||||||
k.Madness += amount
|
|
||||||
return nil
|
|
||||||
case Manufacturing:
|
|
||||||
k.Manufacturing += amount
|
|
||||||
return nil
|
|
||||||
case Militarism:
|
|
||||||
k.Militarism += amount
|
|
||||||
return nil
|
|
||||||
case Mining:
|
|
||||||
k.Mining += amount
|
|
||||||
return nil
|
|
||||||
case ParksExpense:
|
|
||||||
k.ParksExpense += amount
|
|
||||||
return nil
|
|
||||||
case Publishing:
|
|
||||||
k.Publishing += amount
|
|
||||||
return nil
|
|
||||||
case Rebellion:
|
|
||||||
k.Rebellion += amount
|
|
||||||
return nil
|
|
||||||
case Scavenging:
|
|
||||||
k.Scavenging += amount
|
|
||||||
return nil
|
|
||||||
case Secrecy:
|
|
||||||
k.Secrecy += amount
|
|
||||||
return nil
|
|
||||||
case Welfare:
|
|
||||||
k.Welfare += amount
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("cannot add %f to %q: %w", amount, which, ErrNoFieldLabel)
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package koboldsim
|
package koboldsim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
@ -47,3 +49,23 @@ func clamp[T constraints.Ordered](a, b, c T) T {
|
|||||||
// `a` is neither most nor least; therefore, `a` is mid
|
// `a` is neither most nor least; therefore, `a` is mid
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrWrappedPanic = errors.New("panic")
|
||||||
|
|
||||||
|
// try catches a panic in the provided func and demotes it to an error, if any
|
||||||
|
// panic occurs. The returned error, if any, wraps `ErrWrappedPanic`. If the
|
||||||
|
// panic argument is itself an error, it is also wrapped; otherwise, it is
|
||||||
|
// stringified into the error message using `%v`.
|
||||||
|
func try(f func()) (finalErr error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if e, ok := r.(error); ok {
|
||||||
|
finalErr = fmt.Errorf("%w: %w", ErrWrappedPanic, e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
finalErr = fmt.Errorf("%w: %v", ErrWrappedPanic, r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user