From 95a30cb5224d9cab13f8e6417333bb55ebb857eb Mon Sep 17 00:00:00 2001 From: Rakeela Date: Wed, 5 Apr 2023 20:26:57 -0700 Subject: [PATCH] Foreign Relations, Forestry, and a New Issue I guess this project will continue growing for now. --- koboldsim/cards.go | 119 +++++++++++++++++++++++++++++++++++++++++++-- koboldsim/stats.go | 40 +++++++++++++-- 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/koboldsim/cards.go b/koboldsim/cards.go index e3c026a..2d0a7d1 100644 --- a/koboldsim/cards.go +++ b/koboldsim/cards.go @@ -18,6 +18,7 @@ var cards = []Card{ p.Stats.ScavengingIncome += 0.01 p.Stats.WarExpense += 0.02 p.Stats.FoodSupply += 0.01 + p.Stats.ForeignRelations -= 0.02 return cardsim.MsgStr("Kobolds are known to be born warriors."), nil }, Undo: func(p *Player) error { @@ -25,6 +26,7 @@ var cards = []Card{ p.Stats.ScavengingIncome -= 0.01 p.Stats.WarExpense -= 0.02 p.Stats.FoodSupply -= 0.01 + p.Stats.ForeignRelations += 0.02 return nil }, CanDo: YesWeCan, @@ -37,6 +39,7 @@ var cards = []Card{ p.Stats.MiningIncome += 0.02 p.Stats.BureaucracyExpense += 0.01 p.Stats.FoodSupply -= 0.01 + p.Stats.Secrecy += 0.02 return cardsim.MsgStr("Kobolds are known to be cowards hiding in the dark."), nil }, Undo: func(p *Player) error { @@ -44,6 +47,7 @@ var cards = []Card{ p.Stats.MiningIncome -= 0.02 p.Stats.BureaucracyExpense -= 0.01 p.Stats.FoodSupply += 0.01 + p.Stats.Secrecy -= 0.02 return nil }, CanDo: YesWeCan, @@ -57,6 +61,7 @@ var cards = []Card{ p.Stats.WarExpense -= 0.02 p.Stats.EducationExpense += 0.01 p.Stats.FoodSupply -= 0.01 + p.Stats.ForeignRelations += 0.02 return cardsim.MsgStr("An undefended hunting outpost near the surface was recently wiped out by a raid."), nil }, Undo: func(p *Player) error { @@ -65,6 +70,7 @@ var cards = []Card{ p.Stats.WarExpense += 0.02 p.Stats.EducationExpense -= 0.01 p.Stats.FoodSupply += 0.01 + p.Stats.ForeignRelations -= 0.02 return nil }, CanDo: YesWeCan, @@ -236,6 +242,7 @@ var cards = []Card{ p.Stats.GadgetryIncome += 0.01 p.Stats.ScavengingIncome += 0.01 p.Stats.FoodSupply += 0.01 + p.Stats.Secrecy += 0.05 return cardsim.MsgStr("Nobody ever meets a kobold merchant."), nil }, Undo: func(p *Player) error { @@ -246,6 +253,7 @@ var cards = []Card{ p.Stats.GadgetryIncome -= 0.01 p.Stats.ScavengingIncome -= 0.01 p.Stats.FoodSupply -= 0.01 + p.Stats.Secrecy -= 0.05 return nil }, CanDo: YesWeCan, @@ -266,6 +274,8 @@ var cards = []Card{ p.Stats.ForeignRelExpense += 0.01 p.Stats.WarExpense -= 0.01 p.Stats.ScavengingIncome -= 0.01 + p.Stats.Secrecy -= 0.10 + p.Stats.ForeignRelations += 0.05 return cardsim.MsgStr("The economic planning office formally plans for attrition among its merchants."), nil }, Undo: func(p *Player) error { @@ -281,6 +291,8 @@ var cards = []Card{ p.Stats.ForeignRelExpense -= 0.01 p.Stats.WarExpense += 0.01 p.Stats.ScavengingIncome += 0.01 + p.Stats.Secrecy += 0.10 + p.Stats.ForeignRelations -= 0.05 return nil }, CanDo: YesWeCan, @@ -296,6 +308,7 @@ var cards = []Card{ p.Stats.GadgetryIncome += 0.03 p.Stats.MiningIncome -= 0.01 p.Stats.ManufacturingIncome -= 0.01 + p.Stats.HiddenRelPenalty += 0.02 // High is bad on this hidden stat. return cardsim.MsgStr("Kobold merchants are instantly suspected of black market connections."), nil }, Undo: func(p *Player) error { @@ -306,6 +319,7 @@ var cards = []Card{ p.Stats.GadgetryIncome -= 0.03 p.Stats.MiningIncome += 0.01 p.Stats.ManufacturingIncome += 0.01 + p.Stats.HiddenRelPenalty -= 0.02 return nil }, CanDo: YesWeCan, @@ -318,6 +332,7 @@ var cards = []Card{ p.Stats.ConstructionIncome += 0.01 p.Stats.LogisticsExpense += 0.06 p.Stats.FoodSupply -= 0.01 + p.Stats.Secrecy += 0.15 return cardsim.MsgStr("The vast network of caverns under the surface of the world is not a natural phenomenon."), nil }, Undo: func(p *Player) error { @@ -325,6 +340,7 @@ var cards = []Card{ p.Stats.ConstructionIncome -= 0.01 p.Stats.LogisticsExpense -= 0.06 p.Stats.FoodSupply += 0.01 + p.Stats.Secrecy -= 0.15 return nil }, CanDo: YesWeCan, @@ -352,7 +368,7 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr("The surfacers' governments would certainly prefer us to abandon our underworld connections in their cities. Do we care about that? We'd be giving up some excellent profits."), }, &BasicPolicy{ - UnenactedDesc: cardsim.MsgStr("Some of the miners would be heartbroken by abandoning the dream of underground roads, but the tax savings would be significant."), + UnenactedDesc: cardsim.MsgStr("Some of the miners would be heartbroken by abandoning the dream of underground roads, but the tax savings would be significant. Reducing our trade focus on other kobolds does however carry some risk."), }, }, }, @@ -408,14 +424,16 @@ var cards = []Card{ p.Stats.ManufacturingIncome += 0.01 p.Stats.ParksExpense += 0.03 p.Stats.FoodSupply += 0.01 + p.Stats.Secrecy -= 0.10 return cardsim.MsgStr("Surfacers stink less in the nation's vicinity."), nil - }, // Reminder: When a Secrecy stat is implemented charge this option a secrecy penalty. + }, Undo: func(p *Player) error { p.Stats.ConstructionIncome -= 0.02 p.Stats.HospitalityIncome -= 0.03 p.Stats.ManufacturingIncome -= 0.01 p.Stats.ParksExpense -= 0.03 p.Stats.FoodSupply -= 0.01 + p.Stats.Secrecy += 0.10 return nil }, CanDo: YesWeCan, @@ -435,8 +453,101 @@ var cards = []Card{ CanDo: YesWeCan, }, }, - }, //End of "A Recipe for Stewed Kobold" policies - }, //End of "A Recipe for Stewed Kobold" card + }, // End of "A Recipe for Stewed Kobold" policies + }, // End of "A Recipe for Stewed Kobold" card + &SwitchingCard{ + Name: cardsim.MsgStr("Raid on Surface Proposed"), //TODO: Make this card arise only if War investment is positive to begin with. + Desc: cardsim.MsgStr("Resources underground are perpetually tight. Even metallurgy is hard, because fuel is scarce. You can rely on neither field nor forest. The scavengers brave the surface regularly to beg, borrow, or steal the resources necessary to your society, but your war planners want to secure resources more aggressively."), + After: ShuffleIntoBottomHalf, + Policies: []Policy{ + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`A scavenger clad in sturdy clothes says, "We need to secure a section of forests on the surface. The surfacers strip too many of the forests bare; if we dispatch patrols ready to fight we can keep them from assarting the forest for their endlessly growing farm communities."`), + EnactedDesc: cardsim.MsgStr("[current policy] The war department maintains your meagre conquest of a stretch of forest on the surface."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.BasePopulation -= 20 + p.Stats.ForestryIncome += 0.03 + p.Stats.WarExpense += 0.01 + p.Stats.FoodSupply += 0.03 + p.Stats.Secrecy -= 0.10 + p.Stats.ForeignRelations -= 0.01 + return cardsim.MsgStr("A bunch of lumberjacks just disappeared in a forest."), nil + }, + Undo: func(p *Player) error { + p.Stats.BasePopulation += 20 + p.Stats.ForestryIncome -= 0.03 + p.Stats.WarExpense -= 0.01 + p.Stats.FoodSupply -= 0.05 + p.Stats.Secrecy += 0.10 + p.Stats.ForeignRelations += 0.01 + return nil + }, + CanDo: YesWeCan, + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`A very scrawny warrior waves a spear over their head and says, "That's not going far enough! We need to seize farmland of our own! Come on, we shouldn't have to eat cave lichen while the surfacers eat roast pig!"`), + EnactedDesc: cardsim.MsgStr("[current policy] The 'ghost farms' in this region are worked by night as kobolds sparing their eyes avoid doing farmwork in daylight."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.BasePopulation -= 40 + p.Stats.AgricultureIncome += 0.01 + p.Stats.WarExpense += 0.02 + p.Stats.FoodSupply += 0.06 + p.Stats.Secrecy -= 0.20 + p.Stats.ForeignRelations -= 0.04 + return cardsim.MsgStr("Some farmers fight like five kobolds, but few fight like forty."), nil + }, + Undo: func(p *Player) error { + p.Stats.BasePopulation += 40 + p.Stats.AgricultureIncome -= 0.01 + p.Stats.WarExpense -= 0.02 + p.Stats.FoodSupply -= 0.06 + p.Stats.Secrecy += 0.20 + p.Stats.ForeignRelations += 0.04 + return nil + }, + CanDo: YesWeCan, + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`A warrior kobold of quiet intensity says, "We shouldn't try to hold terrain on the surface. We'll give ourselves away to surfacers who otherwise can't pinpoint us. Remember that we can't stand against their armies. What we can do without violating secrecy is focus on banditry. We've mapped activity in our area; it's time to go in for a harvest of our own."`), + EnactedDesc: cardsim.MsgStr("[current policy] Your warriors target caravans for intimidation and larceny."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.BasePopulation -= 10 + p.Stats.ScavengingIncome += 0.02 + p.Stats.WarExpense += 0.01 + p.Stats.FoodSupply += 0.01 + p.Stats.HiddenRelPenalty += 0.02 + return cardsim.MsgStr("Some merchants are even cordial as they pay off kobold bandits."), nil + }, + Undo: func(p *Player) error { + p.Stats.BasePopulation += 10 + p.Stats.ScavengingIncome -= 0.02 + p.Stats.WarExpense -= 0.01 + p.Stats.FoodSupply -= 0.01 + p.Stats.HiddenRelPenalty -= 0.02 + return nil + }, + CanDo: YesWeCan, + }, + &VerbosePolicy{ + Default: &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr("Rejecting militarism will set back the war department, but hunger will persist."), + EnactedDesc: cardsim.MsgStr("[current policy] The war department has been rebuked for its aggression."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.Secrecy += 0.01 + p.Stats.WarExpense -= 0.01 + p.Stats.HiddenRelPenalty -= 0.01 + return cardsim.MsgStr("Some of the warriors have had their fervor redirected into economic pursuits."), nil + }, + Undo: func(p *Player) error { + p.Stats.Secrecy -= 0.01 + p.Stats.WarExpense += 0.01 + p.Stats.HiddenRelPenalty += 0.01 + return nil + }, + CanDo: YesWeCan, + }, + }, + }, // End of "Raid on Surface Proposed" policies + }, // End of "Raid on Surface Proposed" card } // end of card list func initDeck(d *cardsim.Deck[*KoboldMine]) { diff --git a/koboldsim/stats.go b/koboldsim/stats.go index e07da05..ca279fc 100644 --- a/koboldsim/stats.go +++ b/koboldsim/stats.go @@ -18,6 +18,7 @@ type KoboldMine struct { ManufacturingIncome float64 `cardsim:"stat" cardsim_name:"Manufacturing Productivity"` PlanarIncome float64 `cardsim:"stat" cardsim_name:"Planar Productivity"` PublishingIncome float64 `cardsim:"stat" cardsim_name:"Publishing Productivity"` + ForestryIncome float64 `cardsim:"stat" cardsim_name:"Forestry Productivity"` FinanceIncome float64 `cardsim:"stat" cardsim_name:"Finance Productivity"` GadgetryIncome float64 `cardsim:"stat" cardsim_name:"Gadgetry Productivity"` FishingIncome float64 `cardsim:"stat" cardsim_name:"Fishing Productivity"` @@ -38,7 +39,10 @@ type KoboldMine struct { ParksExpense float64 `cardsim:"stat" cardsim_name:"Parks and Aesthetics Investment"` FaithExpense float64 `cardsim:"stat" cardsim_name:"Faith Investment"` - FoodSupply float64 `cardsim:"stathidden"` + FoodSupply float64 `cardsim:"stathidden"` + ForeignRelations float64 `cardsim:"stathidden"` + HiddenRelPenalty float64 `cardsim:"stathidden"` + Secrecy float64 `cardsim:"stathidden"` // AnotherExpense float64 `cardsim:"hiddenround5"` // A different way of adding stats that is slightly more empowering. @@ -67,7 +71,7 @@ func (k *KoboldMine) StatTaxRate() float64 { } func (k *KoboldMine) Kobolds() int64 { - return int64(k.BasePopulation * k.FoodSupply * (1 - 0.5*(k.StatObesity()/100))) + return int64(k.BasePopulation * k.FoodSupply * (1 - 0.5*(k.StatObesity()/100)) * (1 + k.TrueForeignRelations())) } func (k *KoboldMine) DisplayedFoodSupply() float64 { @@ -75,7 +79,19 @@ func (k *KoboldMine) DisplayedFoodSupply() float64 { } func (k *KoboldMine) StatObesity() float64 { - return 100 / (1 + math.Exp(-0.05*(k.DisplayedFoodSupply()-37))) + return 100 / (2.3 + math.Exp(-0.04*(k.DisplayedFoodSupply()-37))) +} + +func (k *KoboldMine) TrueForeignRelations() float64 { + return (1 - math.Max(math.Min(k.Secrecy, 1), 0)) * (math.Max(math.Min(k.ForeignRelations, 1), -1) - k.HiddenRelPenalty) +} + +func (k *KoboldMine) DisplayedForeignRelations() float64 { + return math.Max(math.Min((k.ForeignRelations*100), 100), -100) +} + +func (k *KoboldMine) DisplayedSecrecy() float64 { + return k.Secrecy * 100 } func (k *KoboldMine) Stats() []cardsim.Stat { @@ -113,6 +129,10 @@ func (k *KoboldMine) Stats() []cardsim.Stat { "Book Publishing Income", k.ProductivityFunc(&k.PublishingIncome), ), + cardsim.StatFunc( + "Forestry Income", + k.ProductivityFunc(&k.ForestryIncome), + ), cardsim.StatFunc( "Finance Income", k.ProductivityFunc(&k.FinanceIncome), @@ -193,6 +213,14 @@ func (k *KoboldMine) Stats() []cardsim.Stat { "Total Government Expense", k.TotalGovExpense, ), + cardsim.StatFunc( + "Foreign Relations", + k.DisplayedForeignRelations, + ), + cardsim.StatFunc( + "Secrecy", + k.DisplayedSecrecy, + ), cardsim.StatFunc( "Food Supply", k.DisplayedFoodSupply, @@ -209,7 +237,7 @@ func (k *KoboldMine) Stats() []cardsim.Stat { func NewKoboldMine() *KoboldMine { return &KoboldMine{ - BasePopulation: 1000, + BasePopulation: 1030, MiningIncome: 0.15, ScavengingIncome: 0.1, AlchemyIncome: 0.01, @@ -218,6 +246,7 @@ func NewKoboldMine() *KoboldMine { ManufacturingIncome: 0.10, PlanarIncome: 0.00, PublishingIncome: 0.02, + ForestryIncome: 0.0, FinanceIncome: 0.02, GadgetryIncome: 0.03, FishingIncome: 0.0, @@ -237,5 +266,8 @@ func NewKoboldMine() *KoboldMine { ParksExpense: 0.0, FaithExpense: 0.03, FoodSupply: 0.20, + ForeignRelations: -0.40, + HiddenRelPenalty: -0.01, + Secrecy: .95, } }