Compare commits
4 Commits
e018bd0ad6
...
219ff33d66
Author | SHA1 | Date | |
---|---|---|---|
219ff33d66 | |||
5b860135e9 | |||
d2a00d2044 | |||
ba5171fd67 |
27
.vscode/koboldsimsnippets.code-snippets
vendored
Normal file
27
.vscode/koboldsimsnippets.code-snippets
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
// Place your KoboldSim workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||||
|
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||||
|
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||||
|
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||||
|
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||||
|
// Placeholders with the same ids are connected.
|
||||||
|
// Example:
|
||||||
|
// "Print to console": {
|
||||||
|
// "scope": "javascript,typescript",
|
||||||
|
// "prefix": "log",
|
||||||
|
// "body": [
|
||||||
|
// "console.log('$1');",
|
||||||
|
// "$2"
|
||||||
|
// ],
|
||||||
|
// "description": "Log output to console"
|
||||||
|
// }
|
||||||
|
"KoboldMine Add case": {
|
||||||
|
"scope": "go",
|
||||||
|
"prefix": "case",
|
||||||
|
"body": [
|
||||||
|
"case ${1:field}:",
|
||||||
|
"\tk.${1:field} += amount",
|
||||||
|
"\treturn k.${1:field}",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -8,5 +8,5 @@ require (
|
|||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||||
)
|
)
|
||||||
|
@ -10,34 +10,22 @@ var cards = []Card{
|
|||||||
Desc: cardsim.MsgStr(" A surge of anti-kobold sentiment has been reported by your spies on the surface and your military is concerned that anti-kobold vigilantes will attack the tunnels in the near-future. They want to build up now while doing so is safe."),
|
Desc: cardsim.MsgStr(" A surge of anti-kobold sentiment has been reported by your spies on the surface and your military is concerned that anti-kobold vigilantes will attack the tunnels in the near-future. They want to build up now while doing so is safe."),
|
||||||
After: ShuffleIntoBottomHalf,
|
After: ShuffleIntoBottomHalf,
|
||||||
Policies: []Policy{
|
Policies: []Policy{
|
||||||
&BasicPolicy{
|
&TablePolicy{
|
||||||
UnenactedDesc: cardsim.MsgStr(`Your war chief paces irritably. "We have terrible threats facing us. It's imperative that we build up our numbers in both the military and the domestic sense. I want creches under military control and a good hunting crew to supply them with food."`),
|
UnenactedDesc: cardsim.MsgStr(`Your war chief paces irritably. "We have terrible threats facing us. It's imperative that we build up our numbers in both the military and the domestic sense. I want creches under military control and a good hunting crew to supply them with food."`),
|
||||||
EnactedDesc: cardsim.MsgStr("[current policy] Your war chief is presently monitoring the situation, building up your military, and securing your creches."),
|
EnactedDesc: cardsim.MsgStr("[current policy] Your war chief is presently monitoring the situation, building up your military, and securing your creches."),
|
||||||
Do: func(p *Player) (cardsim.Message, error) {
|
EffectsTable: map[FieldLabel]float64{
|
||||||
p.Stats.BasePopulation += 100
|
BasePopulation: 100,
|
||||||
p.Stats.Scavenging += 1
|
Scavenging: 1,
|
||||||
p.Stats.Militarism += 2
|
Militarism: 2,
|
||||||
p.Stats.FoodSupply += 1
|
FoodSupply: 1,
|
||||||
p.Stats.ForeignRelations -= 2
|
ForeignRelations: -2,
|
||||||
p.Stats.Rebellion -= 3
|
Rebellion: -3,
|
||||||
p.Stats.Madness += 1
|
Madness: 1,
|
||||||
p.Stats.Cruelty += 1
|
Cruelty: 1,
|
||||||
p.Stats.Authoritarianism += 4
|
Authoritarianism: 4,
|
||||||
return cardsim.MsgStr("Kobolds are known to be born warriors."), nil
|
|
||||||
},
|
},
|
||||||
Undo: func(p *Player) error {
|
EnactionDesc: cardsim.MsgStr("Kobolds are known to be born warriors."),
|
||||||
p.Stats.BasePopulation -= 100
|
CanDo: YesWeAlsoCan,
|
||||||
p.Stats.Scavenging -= 1
|
|
||||||
p.Stats.Militarism -= 2
|
|
||||||
p.Stats.FoodSupply -= 1
|
|
||||||
p.Stats.ForeignRelations += 2
|
|
||||||
p.Stats.Rebellion += 3
|
|
||||||
p.Stats.Madness -= 1
|
|
||||||
p.Stats.Cruelty -= 1
|
|
||||||
p.Stats.Authoritarianism -= 4
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
CanDo: YesWeCan,
|
|
||||||
},
|
},
|
||||||
&BasicPolicy{
|
&BasicPolicy{
|
||||||
UnenactedDesc: cardsim.MsgStr(`Your head miner considers the matter worriedly. "Creches under military control? No. That would invite chaos. We need to dig deeper; we can have a peaceful, orderly society if we just get far enough away from surfacers."`),
|
UnenactedDesc: cardsim.MsgStr(`Your head miner considers the matter worriedly. "Creches under military control? No. That would invite chaos. We need to dig deeper; we can have a peaceful, orderly society if we just get far enough away from surfacers."`),
|
||||||
|
@ -9,6 +9,7 @@ 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;
|
||||||
@ -260,6 +261,99 @@ func (b *BasicPolicy) Is(p Policy) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TablePolicy is a Policy where all numerical changes are defined by
|
||||||
|
// adding a constant to some set of fields (defined by `EffectsTable“)
|
||||||
|
// and subtracting it back out when de-enacting. If the currently
|
||||||
|
// enacted option is re-enacted, it refunds the player's action point.
|
||||||
|
type TablePolicy struct {
|
||||||
|
Desc cardsim.Message
|
||||||
|
UnenactedDesc cardsim.Message
|
||||||
|
EnactedDesc cardsim.Message
|
||||||
|
NothingChanged cardsim.Message
|
||||||
|
EffectsTable map[FieldLabel]float64
|
||||||
|
EnactionDesc cardsim.Message
|
||||||
|
CanDo func(*TablePolicy, *Player) bool
|
||||||
|
|
||||||
|
CurrentlyEnacted bool
|
||||||
|
LastEnactedPolicy Policy
|
||||||
|
LastEnactedIdx int
|
||||||
|
}
|
||||||
|
|
||||||
|
func YesWeAlsoCan(*TablePolicy, *Player) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastEnacted notifies t about the last-enacted policy in its group. It updates
|
||||||
|
// t.currentlyEnacted accordingly.
|
||||||
|
func (t *TablePolicy) LastEnacted(i int, p Policy) {
|
||||||
|
t.LastEnactedPolicy = p
|
||||||
|
t.LastEnactedIdx = i
|
||||||
|
t.CurrentlyEnacted = t.Is(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptionText implements CardOption.
|
||||||
|
func (t *TablePolicy) OptionText(*Player) (cardsim.Message, error) {
|
||||||
|
if t.CurrentlyEnacted {
|
||||||
|
if t.EnactedDesc == nil {
|
||||||
|
return nil, ErrUnimplemented
|
||||||
|
}
|
||||||
|
return t.EnactedDesc, nil
|
||||||
|
}
|
||||||
|
if t.UnenactedDesc == nil {
|
||||||
|
return nil, ErrUnimplemented
|
||||||
|
}
|
||||||
|
return t.UnenactedDesc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enact implements CardOption.
|
||||||
|
func (t *TablePolicy) Enact(p *Player) (cardsim.Message, error) {
|
||||||
|
if t.EffectsTable == nil {
|
||||||
|
return nil, ErrUnimplemented
|
||||||
|
}
|
||||||
|
if t.CurrentlyEnacted {
|
||||||
|
p.ActionsRemaining++
|
||||||
|
if t.NothingChanged == nil {
|
||||||
|
t.NothingChanged = cardsim.MsgStr("You continue your current approach.")
|
||||||
|
}
|
||||||
|
return t.NothingChanged, nil
|
||||||
|
}
|
||||||
|
var errs cardsim.ErrorCollector
|
||||||
|
for label, amount := range t.EffectsTable {
|
||||||
|
errs.Add(p.Stats.Add(label, amount))
|
||||||
|
}
|
||||||
|
return t.EnactionDesc, errs.Emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unenact implements Policy.
|
||||||
|
func (t *TablePolicy) Unenact(p *Player) error {
|
||||||
|
if !t.CurrentlyEnacted {
|
||||||
|
return ErrPolicyNotEnacted
|
||||||
|
}
|
||||||
|
var errs cardsim.ErrorCollector
|
||||||
|
for label, amount := range t.EffectsTable {
|
||||||
|
errs.Add(p.Stats.Add(label, -amount))
|
||||||
|
}
|
||||||
|
return errs.Emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled implements CardOption.
|
||||||
|
func (t *TablePolicy) Enabled(p *Player) bool {
|
||||||
|
if t.CurrentlyEnacted {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.CanDo == nil {
|
||||||
|
panic(ErrUnimplemented)
|
||||||
|
}
|
||||||
|
return t.CanDo(t, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TablePolicy) Is(p Policy) bool {
|
||||||
|
if o, ok := p.(*TablePolicy); ok {
|
||||||
|
return o == t
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// A VerbosePolicy is a group of related policies pretending to all be the same
|
// A VerbosePolicy is a group of related policies pretending to all be the same
|
||||||
// policy. Which policy is used is determined by what the previous policy for
|
// policy. Which policy is used is determined by what the previous policy for
|
||||||
// the card was (as reported via a call to LastEnacted):
|
// the card was (as reported via a call to LastEnacted):
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package koboldsim
|
package koboldsim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -164,3 +166,50 @@ func NewKoboldMine() *KoboldMine {
|
|||||||
Secrecy: 95,
|
Secrecy: 95,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FieldLabel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
BasePopulation FieldLabel = "BasePopulation"
|
||||||
|
Scavenging FieldLabel = "Scavenging"
|
||||||
|
Militarism FieldLabel = "Militarism"
|
||||||
|
FoodSupply FieldLabel = "FoodSupply"
|
||||||
|
ForeignRelations FieldLabel = "ForeignRelations"
|
||||||
|
Rebellion FieldLabel = "Rebellion"
|
||||||
|
Madness FieldLabel = "Madness"
|
||||||
|
Cruelty FieldLabel = "Cruelty"
|
||||||
|
Authoritarianism FieldLabel = "Authoritarianism"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (k *KoboldMine) Add(which FieldLabel, amount float64) error {
|
||||||
|
switch which {
|
||||||
|
case BasePopulation:
|
||||||
|
k.BasePopulation += amount
|
||||||
|
return nil
|
||||||
|
case Scavenging:
|
||||||
|
k.Scavenging += amount
|
||||||
|
return nil
|
||||||
|
case Militarism:
|
||||||
|
k.Militarism += amount
|
||||||
|
return nil
|
||||||
|
case FoodSupply:
|
||||||
|
k.FoodSupply += amount
|
||||||
|
return nil
|
||||||
|
case ForeignRelations:
|
||||||
|
k.ForeignRelations += amount
|
||||||
|
return nil
|
||||||
|
case Rebellion:
|
||||||
|
k.Rebellion += amount
|
||||||
|
return nil
|
||||||
|
case Madness:
|
||||||
|
k.Madness += amount
|
||||||
|
return nil
|
||||||
|
case Cruelty:
|
||||||
|
k.Cruelty += amount
|
||||||
|
return nil
|
||||||
|
case Authoritarianism:
|
||||||
|
k.Authoritarianism += amount
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("cannot add %f to %q: %w", amount, which, ErrNoFieldLabel)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user