fix: production with free P.I.

This commit is contained in:
Ilia Denisov
2026-02-06 21:43:47 +02:00
parent 3c4968ab8f
commit 43ba5eb07c
7 changed files with 62 additions and 54 deletions
+9 -10
View File
@@ -199,11 +199,10 @@ func (c *Cache) PlanetProductionCapacity(planetNumber uint) float64 {
return p.ProductionCapacity() - busyResources return p.ProductionCapacity() - busyResources
} }
// TODO: test upgrade & upgrade cancel
func (c *Cache) TurnPlanetProductions() { func (c *Cache) TurnPlanetProductions() {
// cancel upgrade for groups on wiped planets
for sgi := range c.ShipGroupsIndex() { for sgi := range c.ShipGroupsIndex() {
sg := c.ShipGroup(sgi) sg := c.ShipGroup(sgi)
// cancel upgrade for groups on wiped planets
if sg.State() == game.StateUpgrade && !c.MustPlanet(sg.Destination).Owned() { if sg.State() == game.StateUpgrade && !c.MustPlanet(sg.Destination).Owned() {
sg.StateUpgrade = nil sg.StateUpgrade = nil
} }
@@ -215,7 +214,7 @@ func (c *Cache) TurnPlanetProductions() {
r := &c.g.Race[ri] r := &c.g.Race[ri]
// upgrade groups and return to in_orbit state // upgrade groups and return to in_orbit state
productionAvailable := p.ProductionCapacity() productionAvailable := c.PlanetProductionCapacity(pn)
for sg := range c.shipGroupsInUpgrade(p.Number) { for sg := range c.shipGroupsInUpgrade(p.Number) {
cost := sg.StateUpgrade.Cost() cost := sg.StateUpgrade.Cost()
if productionAvailable >= cost { if productionAvailable >= cost {
@@ -235,19 +234,19 @@ func (c *Cache) TurnPlanetProductions() {
} }
case game.ResearchScience: case game.ResearchScience:
sc := c.mustScience(ri, *p.Production.SubjectID) sc := c.mustScience(ri, *p.Production.SubjectID)
ResearchTech(r, p.ProductionCapacity(), sc.Drive.F(), sc.Weapons.F(), sc.Shields.F(), sc.Cargo.F()) ResearchTech(r, productionAvailable, sc.Drive.F(), sc.Weapons.F(), sc.Shields.F(), sc.Cargo.F())
case game.ResearchDrive: case game.ResearchDrive:
ResearchTech(r, p.ProductionCapacity(), 1., 0, 0, 0) ResearchTech(r, productionAvailable, 1., 0, 0, 0)
case game.ResearchWeapons: case game.ResearchWeapons:
ResearchTech(r, p.ProductionCapacity(), 0, 1., 0, 0) ResearchTech(r, productionAvailable, 0, 1., 0, 0)
case game.ResearchShields: case game.ResearchShields:
ResearchTech(r, p.ProductionCapacity(), 0, 0, 1., 0) ResearchTech(r, productionAvailable, 0, 0, 1., 0)
case game.ResearchCargo: case game.ResearchCargo:
ResearchTech(r, p.ProductionCapacity(), 0, 0, 0, 1.) ResearchTech(r, productionAvailable, 0, 0, 0, 1.)
case game.ProductionMaterial: case game.ProductionMaterial:
p.ProduceMaterial() p.ProduceMaterial(productionAvailable)
case game.ProductionCapital: case game.ProductionCapital:
p.ProduceIndustry() p.ProduceIndustry(productionAvailable)
default: default:
panic(fmt.Sprintf("unprocessed production type: '%v' for planet: #%d owner=%v", pt, pn, p.Owner)) panic(fmt.Sprintf("unprocessed production type: '%v' for planet: #%d owner=%v", pt, pn, p.Owner))
} }
+27
View File
@@ -173,6 +173,33 @@ func TestProduceShips(t *testing.T) {
assert.Equal(t, uint(106), c.ShipGroup(0).Number) assert.Equal(t, uint(106), c.ShipGroup(0).Number)
progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress progress = *c.MustPlanet(R0_Planet_0_num).Production.Progress
assert.InDelta(t, 0.0099, progress.F(), 0.00001) // 1.(0099) drones with no CAP on planet assert.InDelta(t, 0.0099, progress.F(), 0.00001) // 1.(0099) drones with no CAP on planet
//
// groups is upgrade state
//
assert.NoError(t, g.PlanetProduction(Race_0.Name, int(R0_Planet_0_num), "MAT", ""))
assert.NoError(t, g.PlanetProduction(Race_0.Name, int(R0_Planet_2_num), "CAP", ""))
assert.NoError(t, c.CreateShips(Race_0_idx, "Drone", R0_Planet_2_num, 5))
c.MustPlanet(R0_Planet_2_num).Resources = 5
c.MustPlanet(R0_Planet_2_num).Population = 100
c.MustPlanet(R0_Planet_2_num).Industry = 100
c.RaceTechLevel(Race_0_idx, game.TechDrive, 1.5)
assert.NoError(t, g.UpgradeGroup(Race_0.Name, 2, "Drive", 0, 0))
assert.NoError(t, g.UpgradeGroup(Race_0.Name, 1, "Drive", 0, 0))
assert.Equal(t, game.StateUpgrade, c.ShipGroup(0).State())
assert.Equal(t, game.StateUpgrade, c.ShipGroup(1).State())
c.MustPlanet(R0_Planet_2_num).Free() // wipe planet as battle result
c.TurnPlanetProductions()
assert.Equal(t, game.StateInOrbit, c.ShipGroup(1).State())
assert.Equal(t, 1.1, c.ShipGroup(1).TechLevel(game.TechDrive).F())
assert.Equal(t, game.StateInOrbit, c.ShipGroup(0).State())
assert.Equal(t, 1.5, c.ShipGroup(0).TechLevel(game.TechDrive).F())
assert.Equal(t, 4346.676567656759, c.MustPlanet(R0_Planet_0_num).Material.F())
} }
func TestProduceShip(t *testing.T) { func TestProduceShip(t *testing.T) {
+4 -11
View File
@@ -423,7 +423,7 @@ func (c *Cache) ReportLocalPlanet(ri int, rep *mr.Report) {
} }
sliceIndexValidate(&rep.LocalPlanet, i) sliceIndexValidate(&rep.LocalPlanet, i)
c.localPlanet(&rep.LocalPlanet[i], p, rep) c.localPlanet(&rep.LocalPlanet[i], p)
// rep.LocalPlanet[i].UnidentifiedPlanet.Number = p.Number // rep.LocalPlanet[i].UnidentifiedPlanet.Number = p.Number
// rep.LocalPlanet[i].UnidentifiedPlanet.X = mr.F(p.X.F()) // rep.LocalPlanet[i].UnidentifiedPlanet.X = mr.F(p.X.F())
// rep.LocalPlanet[i].UnidentifiedPlanet.Y = mr.F(p.Y.F()) // rep.LocalPlanet[i].UnidentifiedPlanet.Y = mr.F(p.Y.F())
@@ -466,7 +466,7 @@ func (c *Cache) ReportOtherPlanet(ri int, rep *mr.Report) {
} }
sliceIndexValidate(&rep.OtherPlanet, i) sliceIndexValidate(&rep.OtherPlanet, i)
c.localPlanet(&rep.OtherPlanet[i].LocalPlanet, p, rep) c.localPlanet(&rep.OtherPlanet[i].LocalPlanet, p)
rep.OtherPlanet[i].Owner = c.g.Race[c.RaceIndex(*p.Owner)].Name rep.OtherPlanet[i].Owner = c.g.Race[c.RaceIndex(*p.Owner)].Name
i++ i++
} }
@@ -728,21 +728,14 @@ func (c *Cache) otherGroup(v *mr.OtherGroup, sg *game.ShipGroup, st *game.ShipTy
v.Mass = mr.F(st.EmptyMass()) v.Mass = mr.F(st.EmptyMass())
} }
func (c *Cache) localPlanet(v *mr.LocalPlanet, p *game.Planet, rep *mr.Report) { func (c *Cache) localPlanet(v *mr.LocalPlanet, p *game.Planet) {
uninhabitedPlanet(&v.UninhabitedPlanet, p) uninhabitedPlanet(&v.UninhabitedPlanet, p)
v.Industry = mr.F(p.Industry.F()) v.Industry = mr.F(p.Industry.F())
v.Population = mr.F(p.Population.F()) v.Population = mr.F(p.Population.F())
v.Colonists = mr.F(p.Colonists.F()) v.Colonists = mr.F(p.Colonists.F())
v.Production = c.PlanetProductionDisplayName(p.Number) v.Production = c.PlanetProductionDisplayName(p.Number)
v.FreeIndustry = mr.F(p.ProductionCapacity())
for _, sgi := range rep.OnPlanetGroupCache[p.Number] {
sg := c.ShipGroup(sgi)
if sg.StateUpgrade == nil {
break
}
// between-turn report: ships upgrading on the planet decreases free indistrial potential // between-turn report: ships upgrading on the planet decreases free indistrial potential
v.FreeIndustry -= mr.F(sg.StateUpgrade.Cost()) v.FreeIndustry = mr.F(c.PlanetProductionCapacity(p.Number))
}
} }
func uninhabitedPlanet(v *mr.UninhabitedPlanet, p *game.Planet) { func uninhabitedPlanet(v *mr.UninhabitedPlanet, p *game.Planet) {
+7 -6
View File
@@ -3,6 +3,7 @@ package controller
import ( import (
"math" "math"
"slices" "slices"
"strings"
e "github.com/iliadenisov/galaxy/internal/error" e "github.com/iliadenisov/galaxy/internal/error"
"github.com/iliadenisov/galaxy/internal/model/game" "github.com/iliadenisov/galaxy/internal/model/game"
@@ -35,14 +36,14 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
} }
upgradeValidTech := map[string]game.Tech{ upgradeValidTech := map[string]game.Tech{
game.TechDrive.String(): game.TechDrive, strings.ToLower(game.TechDrive.String()): game.TechDrive,
game.TechWeapons.String(): game.TechWeapons, strings.ToLower(game.TechWeapons.String()): game.TechWeapons,
game.TechShields.String(): game.TechShields, strings.ToLower(game.TechShields.String()): game.TechShields,
game.TechCargo.String(): game.TechCargo, strings.ToLower(game.TechCargo.String()): game.TechCargo,
game.TechAll.String(): game.TechAll, strings.ToLower(game.TechAll.String()): game.TechAll,
} }
techRequest, ok := upgradeValidTech[techInput] techRequest, ok := upgradeValidTech[strings.ToLower(techInput)]
if !ok { if !ok {
return e.NewTechUnknownError(techInput) return e.NewTechUnknownError(techInput)
} }
@@ -11,17 +11,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// var (
// Cruiser = game.ShipType{
// Name: "Cruiser",
// Drive: 15,
// Armament: 1,
// Weapons: 15,
// Shields: 15,
// Cargo: 0,
// }
// )
func TestBlockUpgradeCost(t *testing.T) { func TestBlockUpgradeCost(t *testing.T) {
assert.Equal(t, 00.0, controller.BlockUpgradeCost(1, 1.0, 1.0)) assert.Equal(t, 00.0, controller.BlockUpgradeCost(1, 1.0, 1.0))
assert.Equal(t, 25.0, controller.BlockUpgradeCost(5, 1.0, 2.0)) assert.Equal(t, 25.0, controller.BlockUpgradeCost(5, 1.0, 2.0))
+7 -8
View File
@@ -76,7 +76,7 @@ func (p Planet) Votes() float64 {
return p.Population.F() / 1000. return p.Population.F() / 1000.
} }
// Производственный потенциал // Производственный потенциал без учёта модернизации кораблей
func (p Planet) ProductionCapacity() float64 { func (p Planet) ProductionCapacity() float64 {
return PlanetProduction(p.Industry.F(), p.Population.F()) return PlanetProduction(p.Industry.F(), p.Population.F())
} }
@@ -104,15 +104,14 @@ func ProducedMaterial(shipMass, progress float64) float64 {
// [x] ind = (res * prod) / (5 * res + 1) // [x] ind = (res * prod) / (5 * res + 1)
// ind = 10 * 1000 / (5 * 10 + 1) = 10000 / 55 = 181.(81) // ind = 10 * 1000 / (5 * 10 + 1) = 10000 / 55 = 181.(81)
// int = 10 * 500 / 55 = 5000 / 55 // int = 10 * 500 / 55 = 5000 / 55
func (p *Planet) ProduceIndustry() { func (p *Planet) ProduceIndustry(freeProduction float64) {
production := p.ProductionCapacity()
var ind float64 var ind float64
if p.Material > 0 { if p.Material > 0 {
ind = math.Min(production/5, p.Material.F()) ind = math.Min(freeProduction/5, p.Material.F())
p.Mat(p.Material.F() - ind) p.Mat(p.Material.F() - ind)
production -= ind * 5. freeProduction -= ind * 5.
} }
ind += (production * p.Resources.F()) / (5.*p.Resources.F() + 1.) ind += (freeProduction * p.Resources.F()) / (5.*p.Resources.F() + 1.)
p.Ind(p.Industry.F() + ind) p.Ind(p.Industry.F() + ind)
if p.Industry > p.Population { if p.Industry > p.Population {
p.Capital += p.Industry - p.Population p.Capital += p.Industry - p.Population
@@ -121,8 +120,8 @@ func (p *Planet) ProduceIndustry() {
} }
// Производство материалов // Производство материалов
func (p *Planet) ProduceMaterial() { func (p *Planet) ProduceMaterial(freeProduction float64) {
p.Material = p.Material.Add(p.ProductionCapacity() * p.Resources.F()) p.Material = p.Material.Add(freeProduction * p.Resources.F())
} }
// Автоматическое увеличение населения на каждом ходу // Автоматическое увеличение населения на каждом ходу
+7 -7
View File
@@ -27,23 +27,23 @@ func TestProduceIndustry(t *testing.T) {
Population: 500, Population: 500,
Industry: 500, Industry: 500,
} }
HW.ProduceIndustry() HW.ProduceIndustry(HW.ProductionCapacity())
assert.InDelta(t, 196.078, HW.Capital.F(), 0.0005) assert.InDelta(t, 196.078, HW.Capital.F(), 0.0005)
HW.Capital = 0 HW.Capital = 0
HW.Material = 200 HW.Material = 200
HW.ProduceIndustry() HW.ProduceIndustry(HW.ProductionCapacity())
assert.Equal(t, 200., HW.Capital.F()) assert.Equal(t, 200., HW.Capital.F())
assert.Equal(t, 0., HW.Material.F()) assert.Equal(t, 0., HW.Material.F())
DW.ProduceIndustry() DW.ProduceIndustry(DW.ProductionCapacity())
assert.InDelta(t, 98.039, DW.Capital.F(), 0.0003) assert.InDelta(t, 98.039, DW.Capital.F(), 0.0003)
DW.Capital = 0 DW.Capital = 0
DW.Material = 100 DW.Material = 100
DW.ProduceIndustry() DW.ProduceIndustry(DW.ProductionCapacity())
assert.Equal(t, 100., DW.Capital.F()) assert.Equal(t, 100., DW.Capital.F())
assert.Equal(t, 0., DW.Material.F()) assert.Equal(t, 0., DW.Material.F())
} }
@@ -57,16 +57,16 @@ func TestProduceMaterial(t *testing.T) {
} }
assert.Equal(t, 0., HW.Material.F()) assert.Equal(t, 0., HW.Material.F())
HW.ProduceMaterial() HW.ProduceMaterial(HW.ProductionCapacity())
assert.Equal(t, 10000., HW.Material.F()) assert.Equal(t, 10000., HW.Material.F())
HW.Industry = 500 HW.Industry = 500
HW.Population = 500 HW.Population = 500
HW.ProduceMaterial() HW.ProduceMaterial(HW.ProductionCapacity())
assert.Equal(t, 15000., HW.Material.F()) assert.Equal(t, 15000., HW.Material.F())
HW.Population = 1000 HW.Population = 1000
HW.ProduceMaterial() HW.ProduceMaterial(HW.ProductionCapacity())
assert.Equal(t, 21250., HW.Material.F()) assert.Equal(t, 21250., HW.Material.F())
} }