From 159508b202d475d071100d6c6f6df30b3842d39a Mon Sep 17 00:00:00 2001 From: Rakeela Date: Tue, 4 Apr 2023 20:23:32 -0700 Subject: [PATCH] New Issue, Food Supply Feature --- koboldsim/cards.go | 190 ++++++++++++++++++++++++++++++++++++++++----- koboldsim/stats.go | 30 +++++-- 2 files changed, 194 insertions(+), 26 deletions(-) diff --git a/koboldsim/cards.go b/koboldsim/cards.go index 97c0ed9..79dfa4a 100644 --- a/koboldsim/cards.go +++ b/koboldsim/cards.go @@ -10,17 +10,19 @@ var cards = []Card{ Policies: []Policy{ &BasicPolicy{ 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 presntly 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) { - p.Stats.Kobolds += 100 + p.Stats.BasePopulation += 100 p.Stats.ScavengingIncome += 0.01 p.Stats.WarExpense += 0.02 + p.Stats.FoodSupply += 0.01 return cardsim.MsgStr("Kobolds are known to be born warriors."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 100 + p.Stats.BasePopulation -= 100 p.Stats.ScavengingIncome -= 0.01 p.Stats.WarExpense -= 0.02 + p.Stats.FoodSupply -= 0.01 return nil }, CanDo: YesWeCan, @@ -29,15 +31,17 @@ var cards = []Card{ 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."`), EnactedDesc: cardsim.MsgStr("[current policy] Your head miner is presently leading a project to dig as far away from the surface as possible."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds += 40 + p.Stats.BasePopulation += 40 p.Stats.MiningIncome += 0.02 p.Stats.BureaucracyExpense += 0.01 + p.Stats.FoodSupply -= 0.01 return cardsim.MsgStr("Kobolds are known to be cowards hiding in the dark."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 40 + p.Stats.BasePopulation -= 40 p.Stats.MiningIncome -= 0.02 p.Stats.BureaucracyExpense -= 0.01 + p.Stats.FoodSupply += 0.01 return nil }, CanDo: YesWeCan, @@ -46,15 +50,19 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr(`Your nursery director is incensed. "Creches under military control? Never! Let young kobolds play! In fact, cut the military just for suggesting this. The threats facing us are completely overstated."`), EnactedDesc: cardsim.MsgStr("[current policy] Military funding has been diverted into early childhood education."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds -= 40 + p.Stats.BasePopulation -= 40 p.Stats.ScavengingIncome -= 0.01 p.Stats.WarExpense -= 0.02 + p.Stats.EducationExpense += 0.01 + p.Stats.FoodSupply -= 0.01 return cardsim.MsgStr("An undefended hunting outpost near the surface was recently wiped out by a raid."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds += 40 + p.Stats.BasePopulation += 40 p.Stats.ScavengingIncome += 0.01 p.Stats.WarExpense += 0.02 + p.Stats.EducationExpense -= 0.01 + p.Stats.FoodSupply += 0.01 return nil }, CanDo: YesWeCan, @@ -63,11 +71,11 @@ var cards = []Card{ Default: &BasicPolicy{ UnenactedDesc: cardsim.MsgStr("This isn't about a disaster and can probably be safely dismissed."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds += 20 + p.Stats.BasePopulation += 20 return cardsim.MsgStr("Creche control doesn't shift that easily."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 20 + p.Stats.BasePopulation -= 20 return nil }, CanDo: YesWeCan, @@ -102,15 +110,17 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr(`Your Minister of Administration is practically jumping for joy. "This is our opportunity to prove that we're a prosperous society and attract some fresh blood! We need to raise salaries in the bureaucracy, grant some time off to our bureaucrats to make sure they can attend, and try to hire talent away from other nations. We'll forge productive trade relations by this, you'll see!`), EnactedDesc: cardsim.MsgStr("[current policy] Your bureaucrats are really looking forward to attending, where they can boast about how the festival boosted their salaries."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds += 80 + p.Stats.BasePopulation += 80 p.Stats.ScavengingIncome += 0.01 p.Stats.BureaucracyExpense += 0.03 + p.Stats.FoodSupply += 0.01 return cardsim.MsgStr("Bureaucrats are considered pillars of society."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 80 + p.Stats.BasePopulation -= 80 p.Stats.ScavengingIncome -= 0.01 p.Stats.BureaucracyExpense -= 0.03 + p.Stats.FoodSupply -= 0.01 return nil }, CanDo: YesWeCan, @@ -119,12 +129,12 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr(`Your Minister of Finance pulls you aside. "This is a good opportunity to head-hunt. Bureaucrats from many nations will be attending. There's got to be some who'll work for less than the ones we've got. There are some terribly threatened or impoverished communities among kobolds.`), EnactedDesc: cardsim.MsgStr("[current policy] Your nation's policy is clear: the festival of bureaucracy is a chance to trade workers with other kobold nations in your attempts to build a more efficient government."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds += 20 + p.Stats.BasePopulation += 20 p.Stats.BureaucracyExpense -= 0.01 return cardsim.MsgStr("Immigrant bureaucrats complain about being under-appreciated."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 20 + p.Stats.BasePopulation -= 20 p.Stats.BureaucracyExpense += 0.01 return nil }, @@ -143,12 +153,12 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr(`Your Minister of Finance greets you exuberantly. "We've trimmed the wages of the bureaucracy beautifully, but maybe we can scout some outright volunteers. Some nations are absolute disasters, after all.`), EnactedDesc: cardsim.MsgStr(`[current policy] It's hard to find volunteer workers at the festival, but your nation is doing its best.`), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds += 10 + p.Stats.BasePopulation += 10 p.Stats.BureaucracyExpense -= 0.02 return cardsim.MsgStr("The local bureaucracy is staffed by volunteer labor."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds -= 10 + p.Stats.BasePopulation -= 10 p.Stats.BureaucracyExpense += 0.02 return nil }, @@ -160,12 +170,12 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr(`One of your non-bureaucrat friends has been in a foul temper. "This festival is everything that's wrong with our society. Life isn't about filling out forms. We ought to snub this festival and outright fire some bureaucrats."`), EnactedDesc: cardsim.MsgStr("Your nation currently bans the International Festival of Bureaucracy. There will be no local celebration without a policy change."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds -= 80 + p.Stats.BasePopulation -= 80 p.Stats.BureaucracyExpense -= 0.04 return cardsim.MsgStr("A wave of bureaucrats just emigrated along with kobolds incensed by the nation's lack of respect for administration."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds += 80 + p.Stats.BasePopulation += 80 p.Stats.BureaucracyExpense += 0.04 return nil }, @@ -176,11 +186,11 @@ var cards = []Card{ UnenactedDesc: cardsim.MsgStr("Some kobolds will attend the festival on their own, and we may face desertions for our lack of interest."), EnactedDesc: cardsim.MsgStr("Some kobolds will attend the festival on their own. No change is expected."), Do: func(p *Player) (cardsim.Message, error) { - p.Stats.Kobolds -= 20 + p.Stats.BasePopulation -= 20 return cardsim.MsgStr("A festival of bureaucracy lured away a few kobolds to other nations."), nil }, Undo: func(p *Player) error { - p.Stats.Kobolds += 20 + p.Stats.BasePopulation += 20 return nil }, CanDo: YesWeCan, @@ -206,8 +216,146 @@ var cards = []Card{ nil, // remember, if using a BasicPolicy, this uses EnactedDesc }, }, - }, - }, + }, //End of "International Festival of Bureaucracy" policies + }, //End of "International Festival of Bureaucracy" card + &SwitchingCard{ + Name: cardsim.MsgStr("Two Kobolds in a Trenchcoat"), + Desc: cardsim.MsgStr("An inevitable concern of kobold nations is the matter of trade. Trade with other kobolds is straightforward, but overland caravans are unsafe. Trade with surfacers is vital... but achieving it is difficult owing to anti-kobold sentiment."), + After: ShuffleIntoBottomHalf, + Policies: []Policy{ + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`Speaking for the conservative opinion, one prospective merchant says, "We need illusions. Our priority needs to be trading to acquire or studying to create artifacts of disguising. The high start-up costs are balanced by free movement in a surface society that frequently detests us."`), + EnactedDesc: cardsim.MsgStr("[current policy] Your merchants rely on magical disguises to avoid being caught as kobolds while doing business on the surface."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.ManufacturingIncome += 0.03 + p.Stats.LogisticsExpense += 0.04 + p.Stats.MiningIncome += 0.01 + p.Stats.AlchemyIncome += 0.01 + p.Stats.GadgetryIncome += 0.01 + p.Stats.ScavengingIncome += 0.01 + p.Stats.FoodSupply += 0.01 + return cardsim.MsgStr("Nobody ever meets a kobold merchant."), nil + }, + Undo: func(p *Player) error { + p.Stats.ManufacturingIncome -= 0.03 + p.Stats.LogisticsExpense -= 0.04 + p.Stats.MiningIncome -= 0.01 + p.Stats.AlchemyIncome -= 0.01 + p.Stats.GadgetryIncome -= 0.01 + p.Stats.ScavengingIncome -= 0.01 + p.Stats.FoodSupply -= 0.01 + return nil + }, + CanDo: YesWeCan, + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`Brave but potentially headstrong, another prospective merchant has attended the meeting with the following plea. "We must take head-on the risk of improving the status of kobolds! Only by bravely attending the surface markets can we hope to achieve a true and lasting peace!`), + EnactedDesc: cardsim.MsgStr(`[currentpolicy] Your merchants represent the nation's peaceful ideals by visiting the surface openly despite occasional casaulties.`), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.BasePopulation -= 15 + p.Stats.ManufacturingIncome += 0.03 + p.Stats.LogisticsExpense += 0.01 + p.Stats.EconPlanExpense += 0.04 + p.Stats.MiningIncome += 0.01 + p.Stats.AlchemyIncome += 0.02 + p.Stats.GadgetryIncome += 0.02 + p.Stats.HospitalityIncome += 0.01 + p.Stats.PublishingIncome += 0.01 + p.Stats.ForeignRelExpense += 0.01 + p.Stats.WarExpense -= 0.01 + p.Stats.ScavengingIncome -= 0.01 + return cardsim.MsgStr("The economic planning office formally plans for attrition among its merchants."), nil + }, + Undo: func(p *Player) error { + p.Stats.BasePopulation += 15 + p.Stats.ManufacturingIncome -= 0.03 + p.Stats.LogisticsExpense -= 0.01 + p.Stats.EconPlanExpense -= 0.04 + p.Stats.MiningIncome -= 0.01 + p.Stats.AlchemyIncome -= 0.02 + p.Stats.GadgetryIncome -= 0.02 + p.Stats.HospitalityIncome -= 0.01 + p.Stats.PublishingIncome -= 0.01 + p.Stats.ForeignRelExpense -= 0.01 + p.Stats.WarExpense += 0.01 + p.Stats.ScavengingIncome += 0.01 + return nil + }, + CanDo: YesWeCan, + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`A shady scavenger has offered to change careers and become a merchant. Their proposal is, "Surfacers aren't all monolithic. If we talk to the ones who are more greedy than prejudiced, we don't need magic or idealism. We can get in contact with lots of people who'll buy lots of things from us, even things that might not have a market if we worked with 'good' merchants."`), + EnactedDesc: cardsim.MsgStr("[current policy] Your merchants work with the underworld of the surface, forging connections with the people who are ironically less likely to murder them."), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.BasePopulation -= 5 + p.Stats.LogisticsExpense += 0.01 + p.Stats.ScavengingIncome += 0.03 + p.Stats.AlchemyIncome += 0.02 + p.Stats.GadgetryIncome += 0.03 + p.Stats.MiningIncome -= 0.01 + p.Stats.ManufacturingIncome -= 0.01 + return cardsim.MsgStr("Kobold merchants are instantly suspected of black market connections."), nil + }, + Undo: func(p *Player) error { + p.Stats.BasePopulation += 5 + p.Stats.LogisticsExpense -= 0.01 + p.Stats.ScavengingIncome -= 0.03 + p.Stats.AlchemyIncome -= 0.02 + p.Stats.GadgetryIncome -= 0.03 + p.Stats.MiningIncome += 0.01 + p.Stats.ManufacturingIncome += 0.01 + return nil + }, + CanDo: YesWeCan, + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr(`A mining forebold registered for the right to attend this meeting, and says, "Surfacers can't be trusted in business and we shouldn't be supporting them with trade. We need underground roads to ease trade with other kobold nations. It's a massive investment in smoothing current tunnels and digging new ones, but think of the reward: a world of underground civilizations supporting each other."`), + EnactedDesc: cardsim.MsgStr(`[currentpolicy] Your merchants have been directed to focus on trade with other kobolds, and your miners are perpetually tunnelling towards other kobold nations in pursuit of the dream of a world of underground roads.`), + Do: func(p *Player) (cardsim.Message, error) { + p.Stats.MiningIncome += 0.05 + p.Stats.ConstructionIncome += 0.01 + p.Stats.LogisticsExpense += 0.06 + p.Stats.FoodSupply -= 0.01 + 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 { + p.Stats.MiningIncome -= 0.05 + p.Stats.ConstructionIncome -= 0.01 + p.Stats.LogisticsExpense -= 0.06 + p.Stats.FoodSupply += 0.01 + return nil + }, + CanDo: YesWeCan, + }, + &VerbosePolicy{ + Default: &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr("Refusing an opportunity to expand trade is merely an opportunity cost. It won't make conditions any better or worse."), + EnactedDesc: cardsim.MsgStr("Refusing an opportunity to expand trade is merely an opportunity cost. It won't make conditions any better or worse."), + Do: func(p *Player) (cardsim.Message, error) { + return cardsim.MsgStr("Kobold merchants are known for their talent at standing on each others' shoulders."), nil + }, + Undo: func(p *Player) error { + return nil + }, + CanDo: YesWeCan, + }, + Variants: []Policy{ + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr("Rejecting the illusion-based merchantry will cost us a great deal in trade and surface food, but we can certainly do it."), + }, + &BasicPolicy{ + UnenactedDesc: cardsim.MsgStr("Rejecting our idealistic approach to surface trade will save a few lives directly, but consider how much we need the food we buy from the surfacers."), + }, + &BasicPolicy{ + 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."), + }, + }, + }, + }, //End of "Two Kobolds in a Trenchcoat" policies + }, //End of "Two Kobolds in a Trenchcoat" card } // end of card list func initDeck(d *cardsim.Deck[*KoboldMine]) { diff --git a/koboldsim/stats.go b/koboldsim/stats.go index 5cc4025..9fe9348 100644 --- a/koboldsim/stats.go +++ b/koboldsim/stats.go @@ -6,7 +6,7 @@ import ( // KoboldMine is the state of a kobold mine. type KoboldMine struct { - Kobolds int64 `cardsim:"stat"` + BasePopulation float64 `cardsim:"stathidden"` MiningIncome float64 `cardsim:"stat" cardsim_name:"Mining Productivity"` ScavengingIncome float64 `cardsim:"stat" cardsim_name:"Scavenging Productivity"` @@ -21,6 +21,7 @@ type KoboldMine struct { FishingIncome float64 `cardsim:"stat" cardsim_name:"Fishing Productivity"` ConstructionIncome float64 `cardsim:"stat" cardsim_name:"Construction Productivity"` + PropagandaExpense float64 `cardsim:"stat" cardsim_name:"Propaganda Investment"` BureaucracyExpense float64 `cardsim:"stat" cardsim_name:"Bureaucracy Investment"` WarExpense float64 `cardsim:"stat" cardsim_name:"War Investment"` QoLExpense float64 `cardsim:"stat" cardsim_name:"QoL Investment"` @@ -35,22 +36,24 @@ 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"` + // AnotherExpense float64 `cardsim:"hiddenround5"` // A different way of adding stats that is slightly more empowering. } func (k *KoboldMine) ProductivityFunc(s *float64) func() float64 { return func() float64 { - return *s * float64(k.Kobolds) + return *s * float64(k.BasePopulation) } } func (k *KoboldMine) TotalSectorIncome() float64 { - return float64(k.Kobolds) * (k.MiningIncome + k.ScavengingIncome + k.AlchemyIncome + k.HospitalityIncome + k.AgricultureIncome + k.ManufacturingIncome + k.PlanarIncome + k.PublishingIncome + k.FinanceIncome + k.GadgetryIncome + k.FishingIncome + k.ConstructionIncome) + return float64(k.Kobolds()) * (k.MiningIncome + k.ScavengingIncome + k.AlchemyIncome + k.HospitalityIncome + k.AgricultureIncome + k.ManufacturingIncome + k.PlanarIncome + k.PublishingIncome + k.FinanceIncome + k.GadgetryIncome + k.FishingIncome + k.ConstructionIncome) } func (k *KoboldMine) TotalGovExpense() float64 { - return float64(k.Kobolds) * (k.BureaucracyExpense + k.WarExpense + k.QoLExpense + k.LogisticsExpense + k.DragonSubsExpense + k.ResearchSubsExpense + k.EducationExpense + k.HealthcareExpense + k.ForeignRelExpense + k.PoliceExpense + k.EconPlanExpense + k.ParksExpense + k.FaithExpense) + return float64(k.Kobolds()) * (k.BureaucracyExpense + k.WarExpense + k.QoLExpense + k.LogisticsExpense + k.DragonSubsExpense + k.ResearchSubsExpense + k.EducationExpense + k.HealthcareExpense + k.ForeignRelExpense + k.PoliceExpense + k.EconPlanExpense + k.ParksExpense + k.FaithExpense) } func (k *KoboldMine) Taxation() float64 { @@ -61,6 +64,14 @@ func (k *KoboldMine) StatTaxRate() float64 { return k.Taxation() } +func (k *KoboldMine) Kobolds() int64 { + return int64(k.BasePopulation * k.FoodSupply) +} + +func (k *KoboldMine) DisplayedFoodSupply() float64 { + return (k.FoodSupply - 1) * 100 +} + func (k *KoboldMine) Stats() []cardsim.Stat { stats := cardsim.ExtractStats(k) funcs := []cardsim.Stat{ @@ -172,6 +183,14 @@ func (k *KoboldMine) Stats() []cardsim.Stat { "Total Government Expense", k.TotalGovExpense, ), + cardsim.StatFunc( + "Food Supply", + k.DisplayedFoodSupply, + ), + cardsim.StatFunc( + "Kobolds", + k.Kobolds, + ), } stats = append(stats, funcs...) // cardsim.SortStats(stats) @@ -180,7 +199,7 @@ func (k *KoboldMine) Stats() []cardsim.Stat { func NewKoboldMine() *KoboldMine { return &KoboldMine{ - Kobolds: 1000, + BasePopulation: 1000, MiningIncome: 0.15, ScavengingIncome: 0.1, AlchemyIncome: 0.01, @@ -206,5 +225,6 @@ func NewKoboldMine() *KoboldMine { EconPlanExpense: 0.02, ParksExpense: 0.0, FaithExpense: 0.03, + FoodSupply: 0.20, } }