package game import ( "slices" "github.com/google/uuid" e "github.com/iliadenisov/galaxy/internal/error" ) type ProductionType string const ( ProductionNone ProductionType = "-" ProductionMaterial ProductionType = "MAT" // Сырьё ProductionCapital ProductionType = "CAP" // Промышленность ResearchDrive ProductionType = "DRIVE" ResearchWeapons ProductionType = "WEAPONS" ResearchShields ProductionType = "SHIELDS" ResearchCargo ProductionType = "CARGO" ResearchScience ProductionType = "SCIENCE" ProductionShip ProductionType = "SHIP" ) type Production struct { Type ProductionType `json:"type"` SubjectID *uuid.UUID `json:"subjectId"` Progress *float64 `json:"progress"` } func (p ProductionType) AsType(subject uuid.UUID) Production { switch p { case ResearchScience, ProductionShip: return Production{Type: p, SubjectID: &subject} default: return Production{Type: p, SubjectID: nil} } } func (g Game) PlanetProduction(raceName string, planetNumber int, prodType, subject string) error { ri, err := g.raceIndex(raceName) if err != nil { return err } var prod ProductionType switch ProductionType(prodType) { case ProductionMaterial: prod = ProductionMaterial case ProductionCapital: prod = ProductionCapital case ResearchDrive: prod = ResearchDrive case ResearchWeapons: prod = ResearchWeapons case ResearchShields: prod = ResearchShields case ResearchCargo: prod = ResearchCargo case ResearchScience: prod = ResearchScience case ProductionShip: prod = ProductionShip default: return e.NewProductionInvalidError(prodType) } return g.planetProductionInternal(ri, planetNumber, prod, subject) } func (g Game) planetProductionInternal(ri int, number int, prod ProductionType, subj string) error { if number < 0 { return e.NewPlanetNumberError(number) } i := slices.IndexFunc(g.Map.Planet, func(p Planet) bool { return p.Number == uint(number) }) if i < 0 { return e.NewEntityNotExistsError("planet #%d", number) } if g.Map.Planet[i].Owner != g.Race[ri].ID { return e.NewEntityNotOwnedError("planet #%d", number) } g.Map.Planet[i].Production.Progress = nil var subjectID *uuid.UUID if (prod == ResearchScience || prod == ProductionShip) && subj == "" { return e.NewEntityTypeNameValidationError("%s=%q", prod, subj) } if prod == ResearchScience { i := slices.IndexFunc(g.Race[ri].Sciences, func(s Science) bool { return s.Name == subj }) if i < 0 { return e.NewEntityNotExistsError("science %w", subj) } subjectID = &g.Race[ri].Sciences[i].ID } if prod == ProductionShip { i := slices.IndexFunc(g.Race[ri].ShipTypes, func(st ShipType) bool { return st.Name == subj }) if i < 0 { return e.NewEntityNotExistsError("ship type %w", subj) } if g.Map.Planet[i].Production.Type == ProductionShip && g.Map.Planet[i].Production.SubjectID != nil && *g.Map.Planet[i].Production.SubjectID == g.Race[ri].ShipTypes[i].ID { // Planet already produces this ship type, keeping progress intact return nil } subjectID = &g.Race[ri].ShipTypes[i].ID var progress float64 = 0. g.Map.Planet[i].Production.Progress = &progress } if g.Map.Planet[i].Production.Type == ProductionShip { if g.Map.Planet[i].Production.SubjectID == nil { return e.NewGameStateError("planet #%d produces ship but SubjectID is empty", g.Map.Planet[i].Number) } s := *g.Map.Planet[i].Production.SubjectID if g.Map.Planet[i].Production.Progress == nil { return e.NewGameStateError("planet #%d produces ship but Progress is empty", g.Map.Planet[i].Number) } progress := *g.Map.Planet[i].Production.Progress i := slices.IndexFunc(g.Race[ri].ShipTypes, func(st ShipType) bool { return st.ID == s }) if i < 0 { return e.NewGameStateError("planet #%d produces ship but ShipType was not found for race %s", g.Map.Planet[i].Number, g.Race[ri].Name) } mat, _ := g.Race[ri].ShipTypes[i].ProductionCost() extra := mat * progress g.Map.Planet[i].Material += extra } g.Map.Planet[i].Production.Type = prod g.Map.Planet[i].Production.SubjectID = subjectID return nil }