race quit, transfer state, refactor
This commit is contained in:
@@ -43,7 +43,7 @@ func (c *Cache) ShipGroupShipClass(groupIndex int) *game.ShipType {
|
|||||||
func (c *Cache) RaceIndex(ID uuid.UUID) int {
|
func (c *Cache) RaceIndex(ID uuid.UUID) int {
|
||||||
if c.cacheRaceIndexByID == nil {
|
if c.cacheRaceIndexByID == nil {
|
||||||
c.cacheRaceIndexByID = make(map[uuid.UUID]int)
|
c.cacheRaceIndexByID = make(map[uuid.UUID]int)
|
||||||
for i := range c.g.Race {
|
for i := range c.listRaceIdx() {
|
||||||
c.cacheRaceIndexByID[c.g.Race[i].ID] = i
|
c.cacheRaceIndexByID[c.g.Race[i].ID] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
e "github.com/iliadenisov/galaxy/internal/error"
|
||||||
|
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c Controller) QuitGame(actor string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Cache.g.Race[ri].TTL = 3
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Controller) GiveVotes(actor, acceptor string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rec, err := c.Cache.validRace(acceptor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Cache.g.Race[ri].VoteFor = c.Cache.g.Race[rec].ID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: remove, not a command
|
||||||
|
func (c Controller) Relation(actor, acceptor string) (game.Relation, error) {
|
||||||
|
r1, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return game.Relation(""), err
|
||||||
|
}
|
||||||
|
r2, err := c.Cache.validRace(acceptor)
|
||||||
|
if err != nil {
|
||||||
|
return game.Relation(""), err
|
||||||
|
}
|
||||||
|
return c.Cache.Relation(r1, r2), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Controller) UpdateRelation(actor, acceptor string, rel game.Relation) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var other int
|
||||||
|
if actor == acceptor {
|
||||||
|
other = ri
|
||||||
|
} else if other, err = c.Cache.validRace(acceptor); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.UpdateRelation(ri, other, rel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) JoinShipGroupToFleet(actor, fleetName string, group, count uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.JoinShipGroupToFleet(ri, fleetName, group, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) JoinFleets(actor, fleetSourceName, fleetTargetName string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.JoinFleets(ri, fleetSourceName, fleetTargetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) SendFleet(actor, fleetName string, planetNumber uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fi, ok := c.Cache.fleetIndex(ri, fleetName)
|
||||||
|
if !ok {
|
||||||
|
return e.NewEntityNotExistsError("fleet %q", fleetName)
|
||||||
|
}
|
||||||
|
return c.Cache.SendFleet(ri, fi, planetNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) RenamePlanet(actor string, planetNumber int, typeName string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.RenamePlanet(ri, planetNumber, typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) PlanetProduction(actor string, planetNumber int, prodType, subject string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var prod game.ProductionType
|
||||||
|
switch game.ProductionType(strings.ToUpper(prodType)) {
|
||||||
|
case game.ProductionMaterial:
|
||||||
|
prod = game.ProductionMaterial
|
||||||
|
case game.ProductionCapital:
|
||||||
|
prod = game.ProductionCapital
|
||||||
|
case game.ResearchDrive:
|
||||||
|
prod = game.ResearchDrive
|
||||||
|
case game.ResearchWeapons:
|
||||||
|
prod = game.ResearchWeapons
|
||||||
|
case game.ResearchShields:
|
||||||
|
prod = game.ResearchShields
|
||||||
|
case game.ResearchCargo:
|
||||||
|
prod = game.ResearchCargo
|
||||||
|
case game.ResearchScience:
|
||||||
|
prod = game.ResearchScience
|
||||||
|
case game.ProductionShip:
|
||||||
|
prod = game.ProductionShip
|
||||||
|
default:
|
||||||
|
return e.NewProductionInvalidError(prodType)
|
||||||
|
}
|
||||||
|
return c.Cache.PlanetProduction(ri, planetNumber, prod, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) SetRoute(actor, loadType string, origin, destination uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rt, ok := game.RouteTypeSet[loadType]
|
||||||
|
if !ok {
|
||||||
|
return e.NewCargoTypeInvalidError(loadType)
|
||||||
|
}
|
||||||
|
return c.Cache.SetRoute(ri, rt, origin, destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) RemoveRoute(actor, loadType string, origin uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rt, ok := game.RouteTypeSet[loadType]
|
||||||
|
if !ok {
|
||||||
|
return e.NewCargoTypeInvalidError(loadType)
|
||||||
|
}
|
||||||
|
return c.Cache.RemoveRoute(ri, rt, origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) CreateScience(actor, typeName string, drive, weapons, shields, cargo float64) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.CreateScience(ri, typeName, drive, weapons, shields, cargo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) DeleteScience(actor, typeName string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.DeleteScience(ri, typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) CreateShipType(actor, typeName string, drive float64, ammo int, weapons, shileds, cargo float64) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.CreateShipType(ri, typeName, drive, ammo, weapons, shileds, cargo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) MergeShipType(actor, name, targetName string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.MergeShipType(ri, name, targetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) DeleteShipType(actor, typeName string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.DeleteShipType(ri, typeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) SendGroup(actor string, groupIndex, planetNumber, quantity uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.SendGroup(ri, groupIndex, planetNumber, quantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) UpgradeGroup(actor string, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.UpgradeGroup(ri, groupIndex, techInput, limitShips, limitLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) JoinEqualGroups(actor string) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Cache.JoinEqualGroups(ri)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) BreakGroup(actor string, groupIndex, quantity uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.BreakGroup(ri, groupIndex, quantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) DisassembleGroup(actor string, groupIndex, quantity uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.DisassembleGroup(ri, groupIndex, quantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) LoadCargo(actor string, groupIndex uint, cargoType string, ships uint, quantity float64) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ct, ok := game.CargoTypeSet[cargoType]
|
||||||
|
if !ok {
|
||||||
|
return e.NewCargoTypeInvalidError(cargoType)
|
||||||
|
}
|
||||||
|
return c.Cache.LoadCargo(ri, groupIndex, ct, ships, quantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) UnloadCargo(actor string, groupIndex uint, ships uint, quantity float64) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.UnloadCargo(ri, groupIndex, ships, quantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) TransferGroup(actor, acceptor string, groupIndex, quantity uint) error {
|
||||||
|
ri, err := c.Cache.validActor(actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
riAccept, err := c.Cache.validRace(acceptor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Cache.TransferGroup(ri, riAccept, groupIndex, quantity)
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ func (c *Cache) AddRace(n string) (int, uuid.UUID) {
|
|||||||
Relations: make([]game.RaceRelation, len(c.g.Race)),
|
Relations: make([]game.RaceRelation, len(c.g.Race)),
|
||||||
}
|
}
|
||||||
c.g.Race = append(c.g.Race, *r)
|
c.g.Race = append(c.g.Race, *r)
|
||||||
for i := range c.g.Race {
|
for i := range c.listRaceIdx() {
|
||||||
if c.g.Race[i].ID != id {
|
if c.g.Race[i].ID != id {
|
||||||
c.g.Race[i].Relations = append(c.g.Race[i].Relations, game.RaceRelation{RaceID: id, Relation: game.RelationPeace})
|
c.g.Race[i].Relations = append(c.g.Race[i].Relations, game.RaceRelation{RaceID: id, Relation: game.RelationPeace})
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ var (
|
|||||||
ID: Race_0_ID,
|
ID: Race_0_ID,
|
||||||
VoteFor: Race_0_ID,
|
VoteFor: Race_0_ID,
|
||||||
Name: "Race_0",
|
Name: "Race_0",
|
||||||
|
TTL: 10,
|
||||||
Tech: map[game.Tech]game.Float{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 1.1,
|
game.TechDrive: 1.1,
|
||||||
game.TechWeapons: 1.2,
|
game.TechWeapons: 1.2,
|
||||||
@@ -28,6 +29,7 @@ var (
|
|||||||
ID: Race_1_ID,
|
ID: Race_1_ID,
|
||||||
VoteFor: Race_1_ID,
|
VoteFor: Race_1_ID,
|
||||||
Name: "Race_1",
|
Name: "Race_1",
|
||||||
|
TTL: 10,
|
||||||
Tech: map[game.Tech]game.Float{
|
Tech: map[game.Tech]game.Float{
|
||||||
game.TechDrive: 2.1,
|
game.TechDrive: 2.1,
|
||||||
game.TechWeapons: 2.2,
|
game.TechWeapons: 2.2,
|
||||||
|
|||||||
@@ -100,14 +100,6 @@ func (c *Cache) FleetSpeedAndMass(fi int) (float64, float64) {
|
|||||||
return speed, mass
|
return speed, mass
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) JoinShipGroupToFleet(raceName, fleetName string, group, count uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.JoinShipGroupToFleet(ri, fleetName, group, count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) JoinShipGroupToFleet(ri int, fleetName string, groupIndex, quantity uint) (err error) {
|
func (c *Cache) JoinShipGroupToFleet(ri int, fleetName string, groupIndex, quantity uint) (err error) {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
name, ok := util.ValidateTypeName(fleetName)
|
name, ok := util.ValidateTypeName(fleetName)
|
||||||
@@ -119,8 +111,8 @@ func (c *Cache) JoinShipGroupToFleet(ri int, fleetName string, groupIndex, quant
|
|||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).State() != game.StateInOrbit {
|
if state := c.ShipGroup(sgi).State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).Number < quantity {
|
if c.ShipGroup(sgi).Number < quantity {
|
||||||
@@ -178,14 +170,6 @@ func (c *Cache) JoinShipGroupToFleet(ri int, fleetName string, groupIndex, quant
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) JoinFleets(raceName, fleetSourceName, fleetTargetName string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.JoinFleets(ri, fleetSourceName, fleetTargetName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) JoinFleets(ri int, fleetSourceName, fleetTargetName string) (err error) {
|
func (c *Cache) JoinFleets(ri int, fleetSourceName, fleetTargetName string) (err error) {
|
||||||
fiSource, ok := c.fleetIndex(ri, fleetSourceName)
|
fiSource, ok := c.fleetIndex(ri, fleetSourceName)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -242,19 +226,21 @@ func (c *Cache) deleteFleetSafe(ri int, name string) error {
|
|||||||
return e.NewEntityInUseError("fleet %s: race %s, group #%d", name, c.g.Race[ri].Name, sg.Number)
|
return e.NewEntityInUseError("fleet %s: race %s, group #%d", name, c.g.Race[ri].Name, sg.Number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.g.Fleets = append(c.g.Fleets[:fi], c.g.Fleets[fi+1:]...)
|
c.unsafeDeleteFleet(fi)
|
||||||
c.cacheFleetIndexByID = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) unsafeDeleteFleet(fi int) {
|
||||||
|
c.validateFleetIndex(fi)
|
||||||
|
c.g.Fleets = append(c.g.Fleets[:fi], c.g.Fleets[fi+1:]...)
|
||||||
|
c.invalidateFleetCache()
|
||||||
|
}
|
||||||
|
|
||||||
// Internal funcs
|
// Internal funcs
|
||||||
|
|
||||||
func (c *Cache) FleetIndex(ID uuid.UUID) (int, bool) {
|
func (c *Cache) FleetIndex(ID uuid.UUID) (int, bool) {
|
||||||
if len(c.cacheFleetIndexByID) == 0 {
|
if len(c.cacheFleetIndexByID) == 0 {
|
||||||
c.cacheFleetIndexByID = make(map[uuid.UUID]int)
|
c.cacheFleetIndex()
|
||||||
for i := range c.g.Fleets {
|
|
||||||
c.cacheFleetIndexByID[c.g.Fleets[i].ID] = i
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if v, ok := c.cacheFleetIndexByID[ID]; ok {
|
if v, ok := c.cacheFleetIndexByID[ID]; ok {
|
||||||
return v, true
|
return v, true
|
||||||
@@ -263,6 +249,17 @@ func (c *Cache) FleetIndex(ID uuid.UUID) (int, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) cacheFleetIndex() {
|
||||||
|
if c.cacheFleetIndexByID != nil {
|
||||||
|
clear(c.cacheFleetIndexByID)
|
||||||
|
} else {
|
||||||
|
c.cacheFleetIndexByID = make(map[uuid.UUID]int)
|
||||||
|
}
|
||||||
|
for i := range c.g.Fleets {
|
||||||
|
c.cacheFleetIndexByID[c.g.Fleets[i].ID] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) MustFleetIndex(ID uuid.UUID) int {
|
func (c *Cache) MustFleetIndex(ID uuid.UUID) int {
|
||||||
if v, ok := c.FleetIndex(ID); ok {
|
if v, ok := c.FleetIndex(ID); ok {
|
||||||
return v
|
return v
|
||||||
|
|||||||
@@ -6,25 +6,13 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) SendFleet(raceName, fleetName string, planetNumber uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fi, ok := c.Cache.fleetIndex(ri, fleetName)
|
|
||||||
if !ok {
|
|
||||||
return e.NewEntityNotExistsError("fleet %q", fleetName)
|
|
||||||
}
|
|
||||||
return c.Cache.SendFleet(ri, fi, planetNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) SendFleet(ri, fi int, planetNumber uint) error {
|
func (c *Cache) SendFleet(ri, fi int, planetNumber uint) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
c.validateFleetIndex(fi)
|
c.validateFleetIndex(fi)
|
||||||
fleetState := c.FleetState(c.g.Fleets[fi].ID)
|
fleetState := c.FleetState(c.g.Fleets[fi].ID)
|
||||||
sourcePlanet, ok := fleetState.AtPlanet()
|
sourcePlanet, ok := fleetState.AtPlanet()
|
||||||
if !ok || game.StateInOrbit != fleetState.State && game.StateLaunched != fleetState.State {
|
if !ok || game.StateInOrbit != fleetState.State && game.StateLaunched != fleetState.State {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", fleetState.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
p1, ok := c.Planet(sourcePlanet)
|
p1, ok := c.Planet(sourcePlanet)
|
||||||
|
|||||||
@@ -118,6 +118,10 @@ func buildGameOnMap(races []string, m generator.Map) (*game.Game, error) {
|
|||||||
gameMap.Planet[i].Number, gameMap.Planet[j].Number = gameMap.Planet[j].Number, gameMap.Planet[i].Number
|
gameMap.Planet[i].Number, gameMap.Planet[j].Number = gameMap.Planet[j].Number, gameMap.Planet[i].Number
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for i := range gameMap.Planet {
|
||||||
|
g.Votes = g.Votes.Add(gameMap.Planet[i].Votes())
|
||||||
|
}
|
||||||
|
|
||||||
g.Map = *gameMap
|
g.Map = *gameMap
|
||||||
|
|
||||||
return g, nil
|
return g, nil
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ func MakeTurn(c *Controller, r Repo) error {
|
|||||||
// Next turn
|
// Next turn
|
||||||
c.Cache.g.Turn += 1
|
c.Cache.g.Turn += 1
|
||||||
|
|
||||||
|
// 00. Вышедшие расы удаляются из списка участвующих рас перед началом просчета очередного хода
|
||||||
|
c.Cache.TurnWipeExtinctRaces()
|
||||||
|
|
||||||
// 01. Корабли, где это возможно, объединяются в группы.
|
// 01. Корабли, где это возможно, объединяются в группы.
|
||||||
c.Cache.TurnMergeEqualShipGroups()
|
c.Cache.TurnMergeEqualShipGroups()
|
||||||
|
|
||||||
@@ -118,6 +121,13 @@ func MakeTurn(c *Controller, r Repo) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := range c.Cache.g.Race {
|
||||||
|
if c.Cache.g.Race[i].Extinct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Cache.g.Race[i].TTL -= 1
|
||||||
|
}
|
||||||
|
|
||||||
// [ ] monitor memory consumption at this point?
|
// [ ] monitor memory consumption at this point?
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
"iter"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
e "github.com/iliadenisov/galaxy/internal/error"
|
e "github.com/iliadenisov/galaxy/internal/error"
|
||||||
@@ -12,14 +11,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) RenamePlanet(raceName string, planetNumber int, typeName string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.RenamePlanet(ri, planetNumber, typeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) RenamePlanet(ri int, number int, name string) error {
|
func (c *Cache) RenamePlanet(ri int, number int, name string) error {
|
||||||
n, ok := util.ValidateTypeName(name)
|
n, ok := util.ValidateTypeName(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -39,35 +30,6 @@ func (c *Cache) RenamePlanet(ri int, number int, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) PlanetProduction(raceName string, planetNumber int, prodType, subject string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var prod game.ProductionType
|
|
||||||
switch game.ProductionType(strings.ToUpper(prodType)) {
|
|
||||||
case game.ProductionMaterial:
|
|
||||||
prod = game.ProductionMaterial
|
|
||||||
case game.ProductionCapital:
|
|
||||||
prod = game.ProductionCapital
|
|
||||||
case game.ResearchDrive:
|
|
||||||
prod = game.ResearchDrive
|
|
||||||
case game.ResearchWeapons:
|
|
||||||
prod = game.ResearchWeapons
|
|
||||||
case game.ResearchShields:
|
|
||||||
prod = game.ResearchShields
|
|
||||||
case game.ResearchCargo:
|
|
||||||
prod = game.ResearchCargo
|
|
||||||
case game.ResearchScience:
|
|
||||||
prod = game.ResearchScience
|
|
||||||
case game.ProductionShip:
|
|
||||||
prod = game.ProductionShip
|
|
||||||
default:
|
|
||||||
return e.NewProductionInvalidError(prodType)
|
|
||||||
}
|
|
||||||
return c.Cache.PlanetProduction(ri, planetNumber, prod, subject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) PlanetProduction(ri int, number int, prod game.ProductionType, subj string) error {
|
func (c *Cache) PlanetProduction(ri int, number int, prod game.ProductionType, subj string) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
if number < 0 {
|
if number < 0 {
|
||||||
|
|||||||
+76
-44
@@ -2,6 +2,7 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"iter"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
e "github.com/iliadenisov/galaxy/internal/error"
|
e "github.com/iliadenisov/galaxy/internal/error"
|
||||||
@@ -9,40 +10,11 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c Controller) Relation(from, to string) (game.Relation, error) {
|
|
||||||
r1, err := c.Cache.raceIndex(from)
|
|
||||||
if err != nil {
|
|
||||||
return game.Relation(""), err
|
|
||||||
}
|
|
||||||
r2, err := c.Cache.raceIndex(to)
|
|
||||||
if err != nil {
|
|
||||||
return game.Relation(""), err
|
|
||||||
}
|
|
||||||
return c.Cache.Relation(r1, r2), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) UpdateRelation(race, opponent string, rel game.Relation) error {
|
|
||||||
ri, err := c.Cache.raceIndex(race)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var other int
|
|
||||||
if race == opponent {
|
|
||||||
other = ri
|
|
||||||
} else if other, err = c.Cache.raceIndex(opponent); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.UpdateRelation(ri, other, rel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) Relation(r1, r2 int) game.Relation {
|
func (c *Cache) Relation(r1, r2 int) game.Relation {
|
||||||
if c.cacheRelation == nil {
|
if c.cacheRelation == nil {
|
||||||
c.cacheRelation = make(map[int]map[int]game.Relation)
|
c.cacheRelation = make(map[int]map[int]game.Relation)
|
||||||
for r1 := range c.g.Race {
|
for r1 := range c.listRaceActingIdx() {
|
||||||
for r2 := range c.g.Race {
|
for r2 := range c.listRaceActingIdx() {
|
||||||
if r1 == r2 {
|
if r1 == r2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -78,19 +50,6 @@ func (c *Cache) updateRelationCache(r1, r2 int, rel game.Relation) {
|
|||||||
c.cacheRelation[r1][r2] = rel
|
c.cacheRelation[r1][r2] = rel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) GiveVotes(race, recipient string) error {
|
|
||||||
ri, err := c.raceIndex(race)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec, err := c.raceIndex(recipient)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.g.Race[ri].VoteFor = c.g.Race[rec].ID
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) Voted(ri int) int {
|
func (c *Cache) Voted(ri int) int {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
return c.RaceIndex(c.g.Race[ri].VoteFor)
|
return c.RaceIndex(c.g.Race[ri].VoteFor)
|
||||||
@@ -123,6 +82,26 @@ func (c *Cache) validateRaceIndex(i int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) validActor(name string) (int, error) {
|
||||||
|
i, err := c.validRace(name)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
c.g.Race[i].TTL = 10
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) validRace(name string) (int, error) {
|
||||||
|
i, err := c.raceIndex(name)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
if c.g.Race[i].Extinct {
|
||||||
|
return -1, e.NewRaceExinctError(name)
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) raceIndex(name string) (int, error) {
|
func (c *Cache) raceIndex(name string) (int, error) {
|
||||||
i := slices.IndexFunc(c.g.Race, func(r game.Race) bool { return r.Name == name })
|
i := slices.IndexFunc(c.g.Race, func(r game.Race) bool { return r.Name == name })
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
@@ -135,3 +114,56 @@ func (c *Cache) raceTechLevel(ri int, t game.Tech, v float64) {
|
|||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
c.g.Race[ri].Tech = c.g.Race[ri].Tech.Set(t, v)
|
c.g.Race[ri].Tech = c.g.Race[ri].Tech.Set(t, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) TurnWipeExtinctRaces() {
|
||||||
|
for i := range c.listRaceActingIdx() {
|
||||||
|
if c.g.Race[i].TTL == 0 {
|
||||||
|
c.wipeRace(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) wipeRace(ri int) {
|
||||||
|
c.validateRaceIndex(ri)
|
||||||
|
r := &c.g.Race[ri]
|
||||||
|
c.g.ShipGroups = slices.DeleteFunc(c.g.ShipGroups, func(v game.ShipGroup) bool { return v.OwnerID == r.ID })
|
||||||
|
c.g.Fleets = slices.DeleteFunc(c.g.Fleets, func(v game.Fleet) bool { return v.OwnerID == r.ID })
|
||||||
|
clear(r.ShipTypes)
|
||||||
|
clear(r.Sciences)
|
||||||
|
for i := range c.g.Map.Planet {
|
||||||
|
p := &c.g.Map.Planet[i]
|
||||||
|
if p.Owner != nil && *p.Owner != r.ID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.Wipe()
|
||||||
|
}
|
||||||
|
r.Votes = 0
|
||||||
|
r.VoteFor = r.ID
|
||||||
|
r.Extinct = true
|
||||||
|
r.TTL = 0
|
||||||
|
c.invalidateFleetCache()
|
||||||
|
c.invalidateShipGroupCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) listRaceActingIdx() iter.Seq[int] {
|
||||||
|
return func(yield func(int) bool) {
|
||||||
|
for i := range c.listRaceIdx() {
|
||||||
|
if c.g.Race[i].Extinct {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !yield(i) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) listRaceIdx() iter.Seq[int] {
|
||||||
|
return func(yield func(int) bool) {
|
||||||
|
for i := range c.g.Race {
|
||||||
|
if !yield(i) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestGiveVotes(t *testing.T) {
|
func TestGiveVotes(t *testing.T) {
|
||||||
c, _ := newCache()
|
c, g := newCache()
|
||||||
|
|
||||||
assert.Equal(t, c.Voted(Race_0_idx), Race_0_idx)
|
assert.Equal(t, c.Voted(Race_0_idx), Race_0_idx)
|
||||||
assert.Equal(t, c.Voted(Race_1_idx), Race_1_idx)
|
assert.Equal(t, c.Voted(Race_1_idx), Race_1_idx)
|
||||||
|
|
||||||
assert.NoError(t, c.GiveVotes(Race_0.Name, Race_1.Name))
|
assert.NoError(t, g.GiveVotes(Race_0.Name, Race_1.Name))
|
||||||
assert.Equal(t, Race_1_idx, c.Voted(Race_0_idx))
|
assert.Equal(t, Race_1_idx, c.Voted(Race_0_idx))
|
||||||
assert.Equal(t, Race_1_idx, c.Voted(Race_1_idx))
|
assert.Equal(t, Race_1_idx, c.Voted(Race_1_idx))
|
||||||
|
|
||||||
assert.ErrorContains(t, c.GiveVotes("UnknownRace", Race_1.Name), e.GenericErrorText(e.ErrInputUnknownRace))
|
assert.ErrorContains(t, g.GiveVotes("UnknownRace", Race_1.Name), e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
assert.ErrorContains(t, c.GiveVotes(Race_0.Name, "UnknownRace"), e.GenericErrorText(e.ErrInputUnknownRace))
|
assert.ErrorContains(t, g.GiveVotes(Race_0.Name, "UnknownRace"), e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
func (c *Cache) Report(t uint, battles []*mr.BattleReport, bombings []*mr.Bombing) iter.Seq[*mr.Report] {
|
func (c *Cache) Report(t uint, battles []*mr.BattleReport, bombings []*mr.Bombing) iter.Seq[*mr.Report] {
|
||||||
report := c.InitReport(t)
|
report := c.InitReport(t)
|
||||||
return func(yield func(*mr.Report) bool) {
|
return func(yield func(*mr.Report) bool) {
|
||||||
for i := range c.g.Race {
|
for i := range c.listRaceActingIdx() {
|
||||||
c.ReportRace(i, report, battles, bombings)
|
c.ReportRace(i, report, battles, bombings)
|
||||||
if !yield(report) {
|
if !yield(report) {
|
||||||
break
|
break
|
||||||
@@ -55,12 +55,13 @@ func (c *Cache) InitReport(t uint) *mr.Report {
|
|||||||
planets[ri] = planets[ri] + 1
|
planets[ri] = planets[ri] + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
for ri := range c.g.Race {
|
for ri := range c.listRaceIdx() {
|
||||||
r := &c.g.Race[ri]
|
r := &c.g.Race[ri]
|
||||||
rr := &report.Player[ri]
|
rr := &report.Player[ri]
|
||||||
|
|
||||||
rr.ID = r.ID
|
rr.ID = r.ID
|
||||||
rr.Name = r.Name
|
rr.Name = r.Name
|
||||||
|
rr.Extinct = r.Extinct
|
||||||
rr.Drive = mr.F(r.TechLevel(game.TechDrive))
|
rr.Drive = mr.F(r.TechLevel(game.TechDrive))
|
||||||
rr.Weapons = mr.F(r.TechLevel(game.TechWeapons))
|
rr.Weapons = mr.F(r.TechLevel(game.TechWeapons))
|
||||||
rr.Shields = mr.F(r.TechLevel(game.TechShields))
|
rr.Shields = mr.F(r.TechLevel(game.TechShields))
|
||||||
|
|||||||
@@ -13,18 +13,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) SetRoute(raceName, loadType string, origin, destination uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rt, ok := game.RouteTypeSet[loadType]
|
|
||||||
if !ok {
|
|
||||||
return e.NewCargoTypeInvalidError(loadType)
|
|
||||||
}
|
|
||||||
return c.Cache.SetRoute(ri, rt, origin, destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) SetRoute(ri int, rt game.RouteType, origin, destination uint) error {
|
func (c *Cache) SetRoute(ri int, rt game.RouteType, origin, destination uint) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
p1, ok := c.Planet(origin)
|
p1, ok := c.Planet(origin)
|
||||||
@@ -48,18 +36,6 @@ func (c *Cache) SetRoute(ri int, rt game.RouteType, origin, destination uint) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) RemoveRoute(raceName, loadType string, origin uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rt, ok := game.RouteTypeSet[loadType]
|
|
||||||
if !ok {
|
|
||||||
return e.NewCargoTypeInvalidError(loadType)
|
|
||||||
}
|
|
||||||
return c.Cache.RemoveRoute(ri, rt, origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) RemoveRoute(ri int, rt game.RouteType, origin uint) error {
|
func (c *Cache) RemoveRoute(ri int, rt game.RouteType, origin uint) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
p1, ok := c.Planet(origin)
|
p1, ok := c.Planet(origin)
|
||||||
@@ -269,23 +245,6 @@ func (c *Cache) selectColUnloadGroup(groups []int) (result iter.Seq[int]) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func MaxOrRandomLoadId(IDtoLoad map[int]float64) int {
|
|
||||||
if len(IDtoLoad) < 2 {
|
|
||||||
panic("IDtoLoad must contain at least 2 keys")
|
|
||||||
}
|
|
||||||
IDs := slices.Collect(maps.Keys(IDtoLoad))
|
|
||||||
slices.SortFunc(IDs, func(id1, id2 int) int { return cmp.Compare(IDtoLoad[id2], IDtoLoad[id1]) })
|
|
||||||
|
|
||||||
// no single winner with highest load
|
|
||||||
if IDtoLoad[IDs[0]] == IDtoLoad[IDs[1]] {
|
|
||||||
// remove IDs which load less than maximum
|
|
||||||
IDs = slices.DeleteFunc(IDs, func(v int) bool { return IDtoLoad[v] < IDtoLoad[IDs[0]] })
|
|
||||||
// IDs[0] will have random index
|
|
||||||
rand.Shuffle(len(IDs), func(i, j int) { IDs[i], IDs[j] = IDs[j], IDs[i] })
|
|
||||||
}
|
|
||||||
return IDs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) listRoutedUnloadShipGroupIds(pn uint, routeType game.RouteType) iter.Seq[int] {
|
func (c *Cache) listRoutedUnloadShipGroupIds(pn uint, routeType game.RouteType) iter.Seq[int] {
|
||||||
return func(yield func(int) bool) {
|
return func(yield func(int) bool) {
|
||||||
yielded := make(map[int]bool)
|
yielded := make(map[int]bool)
|
||||||
@@ -311,3 +270,20 @@ func (c *Cache) listRoutedUnloadShipGroupIds(pn uint, routeType game.RouteType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MaxOrRandomLoadId(IDtoLoad map[int]float64) int {
|
||||||
|
if len(IDtoLoad) < 2 {
|
||||||
|
panic("IDtoLoad must contain at least 2 keys")
|
||||||
|
}
|
||||||
|
IDs := slices.Collect(maps.Keys(IDtoLoad))
|
||||||
|
slices.SortFunc(IDs, func(id1, id2 int) int { return cmp.Compare(IDtoLoad[id2], IDtoLoad[id1]) })
|
||||||
|
|
||||||
|
// no single winner with highest load
|
||||||
|
if IDtoLoad[IDs[0]] == IDtoLoad[IDs[1]] {
|
||||||
|
// remove IDs which load less than maximum
|
||||||
|
IDs = slices.DeleteFunc(IDs, func(v int) bool { return IDtoLoad[v] < IDtoLoad[IDs[0]] })
|
||||||
|
// IDs[0] will have random index
|
||||||
|
rand.Shuffle(len(IDs), func(i, j int) { IDs[i], IDs[j] = IDs[j], IDs[i] })
|
||||||
|
}
|
||||||
|
return IDs[0]
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func TestListRoutedSendGroupIds(t *testing.T) {
|
|||||||
|
|
||||||
// Foreign group -> idx 1
|
// Foreign group -> idx 1
|
||||||
assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 10))
|
assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 10))
|
||||||
assert.NoError(t, g.GiveawayGroup(Race_0.Name, Race_1.Name, 5, 0))
|
assert.NoError(t, g.TransferGroup(Race_0.Name, Race_1.Name, 5, 0))
|
||||||
|
|
||||||
// 5: idx = 4 / Part of the Fleet
|
// 5: idx = 4 / Part of the Fleet
|
||||||
assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 10))
|
assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Freighter, R0_Planet_0_num, 10))
|
||||||
|
|||||||
@@ -10,14 +10,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) CreateScience(raceName, typeName string, drive, weapons, shields, cargo float64) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.CreateScience(ri, typeName, drive, weapons, shields, cargo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) CreateScience(ri int, name string, drive, weapons, shileds, cargo float64) error {
|
func (c *Cache) CreateScience(ri int, name string, drive, weapons, shileds, cargo float64) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
n, ok := util.ValidateTypeName(name)
|
n, ok := util.ValidateTypeName(name)
|
||||||
@@ -55,14 +47,6 @@ func (c *Cache) CreateScience(ri int, name string, drive, weapons, shileds, carg
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) DeleteScience(raceName, typeName string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.DeleteScience(ri, typeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) DeleteScience(ri int, name string) error {
|
func (c *Cache) DeleteScience(ri int, name string) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
sc := slices.IndexFunc(c.g.Race[ri].Sciences, func(s game.Science) bool { return s.Name == name })
|
sc := slices.IndexFunc(c.g.Race[ri].Sciences, func(s game.Science) bool { return s.Name == name })
|
||||||
|
|||||||
@@ -11,14 +11,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) CreateShipType(raceName, typeName string, drive float64, ammo int, weapons, shileds, cargo float64) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.CreateShipType(ri, typeName, drive, ammo, weapons, shileds, cargo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) CreateShipType(ri int, typeName string, drive float64, ammo int, weapons, shileds, cargo float64) error {
|
func (c *Cache) CreateShipType(ri int, typeName string, drive float64, ammo int, weapons, shileds, cargo float64) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
if err := checkShipTypeValues(drive, ammo, weapons, shileds, cargo); err != nil {
|
if err := checkShipTypeValues(drive, ammo, weapons, shileds, cargo); err != nil {
|
||||||
@@ -45,14 +37,6 @@ func (c *Cache) CreateShipType(ri int, typeName string, drive float64, ammo int,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) MergeShipType(race, name, targetName string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(race)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.MergeShipType(ri, name, targetName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) MergeShipType(ri int, name, targetName string) error {
|
func (c *Cache) MergeShipType(ri int, name, targetName string) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
st, sti, ok := c.ShipClass(ri, name)
|
st, sti, ok := c.ShipClass(ri, name)
|
||||||
@@ -101,14 +85,6 @@ func (c *Cache) MergeShipType(ri int, name, targetName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) DeleteShipType(raceName, typeName string) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.DeleteShipType(ri, typeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) DeleteShipType(ri int, name string) error {
|
func (c *Cache) DeleteShipType(ri int, name string) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
st, i, ok := c.ShipClass(ri, name)
|
st, i, ok := c.ShipClass(ri, name)
|
||||||
@@ -136,15 +112,6 @@ func (c *Cache) DeleteShipType(ri int, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShipTypes used for tests only
|
|
||||||
func (c *Controller) ShipTypes(race string) ([]*game.ShipType, error) {
|
|
||||||
ri, err := c.Cache.raceIndex(race)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.Cache.ShipTypes(ri), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShipTypes used for tests only
|
// ShipTypes used for tests only
|
||||||
func (c *Cache) ShipTypes(ri int) []*game.ShipType {
|
func (c *Cache) ShipTypes(ri int) []*game.ShipType {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
|
|||||||
@@ -118,29 +118,39 @@ func (c *Cache) DeleteShipGroup(i int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) DeleteKilledShipGroups() {
|
func (c *Cache) DeleteKilledShipGroups() {
|
||||||
|
keepFleet := make(map[uuid.UUID]bool, len(c.g.Fleets))
|
||||||
for i := len(c.g.ShipGroups) - 1; i >= 0; i-- {
|
for i := len(c.g.ShipGroups) - 1; i >= 0; i-- {
|
||||||
|
if c.g.ShipGroups[i].FleetID != nil {
|
||||||
|
id := *c.g.ShipGroups[i].FleetID
|
||||||
|
keepFleet[id] = keepFleet[id] || c.g.ShipGroups[i].Number > 0
|
||||||
|
}
|
||||||
if c.g.ShipGroups[i].Number == 0 {
|
if c.g.ShipGroups[i].Number == 0 {
|
||||||
c.unsafeDeleteShipGroup(i)
|
c.unsafeDeleteShipGroup(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: delete empty fleets
|
for id, keep := range keepFleet {
|
||||||
}
|
if keep {
|
||||||
|
continue
|
||||||
func (c *Controller) JoinEqualGroups(raceName string) error {
|
}
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
c.unsafeDeleteFleet(c.MustFleetIndex(id))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
c.Cache.JoinEqualGroups(ri)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) TurnMergeEqualShipGroups() {
|
func (c *Cache) TurnMergeEqualShipGroups() {
|
||||||
for i := range c.g.Race {
|
for i := range c.listRaceActingIdx() {
|
||||||
|
c.transferPendingGroups(i)
|
||||||
c.JoinEqualGroups(i)
|
c.JoinEqualGroups(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) transferPendingGroups(ri int) {
|
||||||
|
for sg := range c.listShipGroups(ri) {
|
||||||
|
if sg.State() == game.StateTransfer {
|
||||||
|
sg.StateTransfer = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) JoinEqualGroups(ri int) {
|
func (c *Cache) JoinEqualGroups(ri int) {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
raceGroups := make([]game.ShipGroup, 0)
|
raceGroups := make([]game.ShipGroup, 0)
|
||||||
@@ -183,30 +193,14 @@ func (c *Cache) JoinEqualGroups(ri int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) BreakGroup(raceName string, groupIndex, quantity uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.BreakGroup(ri, groupIndex, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) DisassembleGroup(raceName string, groupIndex, quantity uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.DisassembleGroup(ri, groupIndex, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) DisassembleGroup(ri int, groupIndex, quantity uint) error {
|
func (c *Cache) DisassembleGroup(ri int, groupIndex, quantity uint) error {
|
||||||
sgi, ok := c.raceShipGroupIndex(ri, groupIndex)
|
sgi, ok := c.raceShipGroupIndex(ri, groupIndex)
|
||||||
if !ok {
|
if !ok {
|
||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).State() != game.StateInOrbit {
|
if state := c.ShipGroup(sgi).State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).Number < quantity {
|
if c.ShipGroup(sgi).Number < quantity {
|
||||||
@@ -254,18 +248,6 @@ func (c *Cache) DisassembleGroup(ri int, groupIndex, quantity uint) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) LoadCargo(raceName string, groupIndex uint, cargoType string, ships uint, quantity float64) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ct, ok := game.CargoTypeSet[cargoType]
|
|
||||||
if !ok {
|
|
||||||
return e.NewCargoTypeInvalidError(cargoType)
|
|
||||||
}
|
|
||||||
return c.Cache.LoadCargo(ri, groupIndex, ct, ships, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Корабль может нести только один тип груза одновременно.
|
// Корабль может нести только один тип груза одновременно.
|
||||||
// Возможные типы груза - это колонисты, сырье и промышленность.
|
// Возможные типы груза - это колонисты, сырье и промышленность.
|
||||||
// Груз может быть доставлен на борт корабля с Вашей или не занятой планеты, на которой он имеется.
|
// Груз может быть доставлен на борт корабля с Вашей или не занятой планеты, на которой он имеется.
|
||||||
@@ -277,8 +259,8 @@ func (c *Cache) LoadCargo(ri int, groupIndex uint, ct game.CargoType, ships uint
|
|||||||
if !ok {
|
if !ok {
|
||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
if c.ShipGroup(sgi).State() != game.StateInOrbit {
|
if state := c.ShipGroup(sgi).State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
}
|
}
|
||||||
p, ok := c.Planet(c.ShipGroup(sgi).Destination)
|
p, ok := c.Planet(c.ShipGroup(sgi).Destination)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -337,14 +319,6 @@ func (c *Cache) LoadCargo(ri int, groupIndex uint, ct game.CargoType, ships uint
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) UnloadCargo(raceName string, groupIndex uint, ships uint, quantity float64) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.UnloadCargo(ri, groupIndex, ships, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Промышленность и Сырье могут быть выгружены на любой планете.
|
// Промышленность и Сырье могут быть выгружены на любой планете.
|
||||||
// Колонисты могут быть высажены только на планеты, принадлежащие Вам или на необитаемые планеты.
|
// Колонисты могут быть высажены только на планеты, принадлежащие Вам или на необитаемые планеты.
|
||||||
func (c *Cache) UnloadCargo(ri int, groupIndex uint, ships uint, quantity float64) error {
|
func (c *Cache) UnloadCargo(ri int, groupIndex uint, ships uint, quantity float64) error {
|
||||||
@@ -356,8 +330,8 @@ func (c *Cache) UnloadCargo(ri int, groupIndex uint, ships uint, quantity float6
|
|||||||
if !ok {
|
if !ok {
|
||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
if c.ShipGroup(sgi).State() != game.StateInOrbit {
|
if state := c.ShipGroup(sgi).State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
}
|
}
|
||||||
st := c.ShipGroupShipClass(sgi)
|
st := c.ShipGroupShipClass(sgi)
|
||||||
if st.Cargo < 1 {
|
if st.Cargo < 1 {
|
||||||
@@ -429,19 +403,7 @@ func (c *Cache) unsafeUnloadCargo(sgi int, q float64) {
|
|||||||
p.UnpackCapital()
|
p.UnpackCapital()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) GiveawayGroup(raceName, raceAcceptor string, groupIndex, quantity uint) error {
|
func (c *Cache) TransferGroup(ri, riAccept int, groupIndex, quantity uint) (err error) {
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
riAccept, err := c.Cache.raceIndex(raceAcceptor)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.GiveawayGroup(ri, riAccept, groupIndex, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) GiveawayGroup(ri, riAccept int, groupIndex, quantity uint) (err error) {
|
|
||||||
if ri == riAccept {
|
if ri == riAccept {
|
||||||
return e.NewSameRaceError(c.g.Race[riAccept].Name)
|
return e.NewSameRaceError(c.g.Race[riAccept].Name)
|
||||||
}
|
}
|
||||||
@@ -449,8 +411,13 @@ func (c *Cache) GiveawayGroup(ri, riAccept int, groupIndex, quantity uint) (err
|
|||||||
if !ok {
|
if !ok {
|
||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
if c.ShipGroup(sgi).Number < quantity {
|
sg := c.ShipGroup(sgi)
|
||||||
return e.NewBeakGroupNumberNotEnoughError("%d<%d", c.ShipGroup(sgi).Number, quantity)
|
state := sg.State()
|
||||||
|
if state == game.StateTransfer {
|
||||||
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
|
}
|
||||||
|
if sg.Number < quantity {
|
||||||
|
return e.NewBeakGroupNumberNotEnoughError("%d<%d", sg.Number, quantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
st := c.ShipGroupShipClass(sgi)
|
st := c.ShipGroupShipClass(sgi)
|
||||||
@@ -474,18 +441,22 @@ func (c *Cache) GiveawayGroup(ri, riAccept int, groupIndex, quantity uint) (err
|
|||||||
stAcc = len(c.g.Race[riAccept].ShipTypes) - 1
|
stAcc = len(c.g.Race[riAccept].ShipTypes) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
sg := *(c.ShipGroup(sgi))
|
newGroup := *(sg)
|
||||||
sg.TypeID = c.g.Race[riAccept].ShipTypes[stAcc].ID
|
newGroup.TypeID = c.g.Race[riAccept].ShipTypes[stAcc].ID
|
||||||
sg.Number = uint(quantity)
|
newGroup.Tech = maps.Clone(sg.Tech)
|
||||||
sg.Tech = maps.Clone(sg.Tech)
|
if state == game.StateLaunched {
|
||||||
c.appendShipGroup(riAccept, &sg)
|
newGroup.StateTransfer = true
|
||||||
|
}
|
||||||
|
|
||||||
if quantity == 0 || quantity == c.ShipGroup(sgi).Number {
|
if quantity == 0 || quantity == sg.Number {
|
||||||
c.unsafeDeleteShipGroup(sgi)
|
c.unsafeDeleteShipGroup(sgi)
|
||||||
} else {
|
} else {
|
||||||
c.ShipGroup(sgi).Number -= quantity
|
newGroup.Number = quantity
|
||||||
|
sg.Number -= quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.appendShipGroup(riAccept, &newGroup)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,7 +473,7 @@ func (c *Cache) BreakGroup(ri int, groupIndex, quantity uint) error {
|
|||||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).State() != game.StateInOrbit {
|
if state := c.ShipGroup(sgi).State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/util"
|
"github.com/iliadenisov/galaxy/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) SendGroup(raceName string, groupIndex, planetNumber, quantity uint) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.SendGroup(ri, groupIndex, planetNumber, quantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) SendGroup(ri int, groupIndex, planetNumber, quantity uint) error {
|
func (c *Cache) SendGroup(ri int, groupIndex, planetNumber, quantity uint) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
|
|
||||||
@@ -29,7 +21,7 @@ func (c *Cache) SendGroup(ri int, groupIndex, planetNumber, quantity uint) error
|
|||||||
|
|
||||||
sourcePlanet, ok := c.ShipGroup(sgi).AtPlanet()
|
sourcePlanet, ok := c.ShipGroup(sgi).AtPlanet()
|
||||||
if !ok {
|
if !ok {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", c.ShipGroup(sgi).State())
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ShipGroup(sgi).Number < quantity {
|
if c.ShipGroup(sgi).Number < quantity {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package controller_test
|
package controller_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ func TestBreakGroup(t *testing.T) {
|
|||||||
assert.Nil(t, c.ShipGroup(3).FleetID)
|
assert.Nil(t, c.ShipGroup(3).FleetID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGiveawayGroup(t *testing.T) {
|
func TestTransferGroup(t *testing.T) {
|
||||||
c, g := newCache()
|
c, g := newCache()
|
||||||
assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 11)) // group #1 (0)
|
assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 11)) // group #1 (0)
|
||||||
assert.NoError(t, c.CreateShips(Race_1_idx, ShipType_Cruiser, R1_Planet_1_num, 23)) // group #1 (1)
|
assert.NoError(t, c.CreateShips(Race_1_idx, ShipType_Cruiser, R1_Planet_1_num, 23)) // group #1 (1)
|
||||||
@@ -178,25 +179,25 @@ func TestGiveawayGroup(t *testing.T) {
|
|||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 1)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 1)
|
||||||
|
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup("UnknownRace", Race_1.Name, 2, 0),
|
g.TransferGroup("UnknownRace", Race_1.Name, 2, 0),
|
||||||
e.GenericErrorText(e.ErrInputUnknownRace))
|
e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup(Race_0.Name, "UnknownRace", 2, 0),
|
g.TransferGroup(Race_0.Name, "UnknownRace", 2, 0),
|
||||||
e.GenericErrorText(e.ErrInputUnknownRace))
|
e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup(Race_0.Name, Race_0.Name, 2, 0),
|
g.TransferGroup(Race_0.Name, Race_0.Name, 2, 0),
|
||||||
e.GenericErrorText(e.ErrInputSameRace))
|
e.GenericErrorText(e.ErrInputSameRace))
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup(Race_0.Name, Race_1.Name, 555, 0),
|
g.TransferGroup(Race_0.Name, Race_1.Name, 555, 0),
|
||||||
e.GenericErrorText(e.ErrInputEntityNotExists))
|
e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup(Race_0.Name, Race_1.Name, 2, 18),
|
g.TransferGroup(Race_0.Name, Race_1.Name, 2, 18),
|
||||||
e.GenericErrorText(e.ErrBeakGroupNumberNotEnough))
|
e.GenericErrorText(e.ErrBeakGroupNumberNotEnough))
|
||||||
assert.ErrorContains(t,
|
assert.ErrorContains(t,
|
||||||
g.GiveawayGroup(Race_0.Name, Race_1.Name, 1, 0),
|
g.TransferGroup(Race_0.Name, Race_1.Name, 1, 0),
|
||||||
e.GenericErrorText(e.ErrGiveawayGroupShipsTypeNotEqual))
|
e.GenericErrorText(e.ErrGiveawayGroupShipsTypeNotEqual))
|
||||||
|
|
||||||
assert.NoError(t, g.GiveawayGroup(Race_0.Name, Race_1.Name, 2, 11)) // group #2 (3)
|
assert.NoError(t, g.TransferGroup(Race_0.Name, Race_1.Name, 2, 11)) // group #2 (3)
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 2)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 2)
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 2)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 2)
|
||||||
|
|
||||||
@@ -216,14 +217,31 @@ func TestGiveawayGroup(t *testing.T) {
|
|||||||
assert.Equal(t, c.ShipGroup(2).Destination, c.ShipGroup(3).Destination)
|
assert.Equal(t, c.ShipGroup(2).Destination, c.ShipGroup(3).Destination)
|
||||||
assert.Equal(t, c.ShipGroup(2).StateInSpace, c.ShipGroup(3).StateInSpace)
|
assert.Equal(t, c.ShipGroup(2).StateInSpace, c.ShipGroup(3).StateInSpace)
|
||||||
assert.Equal(t, c.ShipGroup(2).StateUpgrade, c.ShipGroup(3).StateUpgrade)
|
assert.Equal(t, c.ShipGroup(2).StateUpgrade, c.ShipGroup(3).StateUpgrade)
|
||||||
|
assert.Equal(t, c.ShipGroup(2).StateTransfer, c.ShipGroup(3).StateTransfer)
|
||||||
assert.Equal(t, c.ShipGroup(3).OwnerID, Race_1_ID)
|
assert.Equal(t, c.ShipGroup(3).OwnerID, Race_1_ID)
|
||||||
assert.Equal(t, c.ShipGroup(3).TypeID, c.MustShipClass(Race_1_idx, Race_0_Gunship).ID)
|
assert.Equal(t, c.ShipGroup(3).TypeID, c.MustShipClass(Race_1_idx, Race_0_Gunship).ID)
|
||||||
assert.Equal(t, c.ShipGroup(3).Number, uint(11))
|
assert.Equal(t, c.ShipGroup(3).Number, uint(11))
|
||||||
assert.Nil(t, c.ShipGroup(3).FleetID)
|
assert.Nil(t, c.ShipGroup(3).FleetID)
|
||||||
|
|
||||||
assert.NoError(t, g.GiveawayGroup(Race_1.Name, Race_0.Name, 2, 11))
|
assert.NoError(t, g.TransferGroup(Race_1.Name, Race_0.Name, 2, 11))
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 3)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 3)
|
||||||
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 1)
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 1)
|
||||||
|
|
||||||
|
assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 1))
|
||||||
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 4)
|
||||||
|
assert.Equal(t, game.StateInOrbit, c.ShipGroup(4).State())
|
||||||
|
assert.NoError(t, g.SendGroup(Race_0.Name, c.ShipGroup(4).Index, R0_Planet_2_num, 0))
|
||||||
|
assert.Equal(t, game.StateLaunched, c.ShipGroup(4).State())
|
||||||
|
assert.Equal(t, c.ShipGroup(4).OwnerID, Race_0_ID)
|
||||||
|
|
||||||
|
assert.NoError(t, g.TransferGroup(Race_0.Name, Race_1.Name, c.ShipGroup(4).Index, 0))
|
||||||
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_0_idx)), 3)
|
||||||
|
assert.Len(t, slices.Collect(c.RaceShipGroups(Race_1_idx)), 2)
|
||||||
|
assert.Equal(t, game.StateTransfer, c.ShipGroup(4).State())
|
||||||
|
assert.Equal(t, c.ShipGroup(4).OwnerID, Race_1_ID)
|
||||||
|
assert.ErrorContains(t,
|
||||||
|
g.TransferGroup(Race_1.Name, Race_0.Name, c.ShipGroup(4).Index, 0),
|
||||||
|
e.GenericErrorText(e.ErrShipsBusy))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadCargo(t *testing.T) {
|
func TestLoadCargo(t *testing.T) {
|
||||||
@@ -540,3 +558,7 @@ func TestShipGroupDestroyItem(t *testing.T) {
|
|||||||
assert.Equal(t, float64(c.ShipGroup(0).Number)*10, c.ShipGroup(0).Load.F())
|
assert.Equal(t, float64(c.ShipGroup(0).Number)*10, c.ShipGroup(0).Load.F())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestState(t *testing.T) {
|
||||||
|
assert.Equal(t, "In_Orbit", fmt.Sprintf("%s", game.StateInOrbit))
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,14 +9,6 @@ import (
|
|||||||
"github.com/iliadenisov/galaxy/internal/model/game"
|
"github.com/iliadenisov/galaxy/internal/model/game"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) UpgradeGroup(raceName string, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
|
||||||
ri, err := c.Cache.raceIndex(raceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.Cache.UpgradeGroup(ri, groupIndex, techInput, limitShips, limitLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShips uint, limitLevel float64) error {
|
||||||
c.validateRaceIndex(ri)
|
c.validateRaceIndex(ri)
|
||||||
sgi, ok := c.raceShipGroupIndex(ri, groupIndex)
|
sgi, ok := c.raceShipGroupIndex(ri, groupIndex)
|
||||||
@@ -26,8 +18,8 @@ func (c *Cache) UpgradeGroup(ri int, groupIndex uint, techInput string, limitShi
|
|||||||
st := c.ShipGroupShipClass(sgi)
|
st := c.ShipGroupShipClass(sgi)
|
||||||
sg := c.ShipGroup(sgi)
|
sg := c.ShipGroup(sgi)
|
||||||
|
|
||||||
if s := sg.State(); s != game.StateInOrbit { // && s != game.StateUpgrade
|
if state := sg.State(); state != game.StateInOrbit {
|
||||||
return e.NewShipsBusyError()
|
return e.NewShipsBusyError("state: %s", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := c.MustPlanet(sg.Destination)
|
p := c.MustPlanet(sg.Destination)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const (
|
|||||||
ErrUpgradeInsufficientResources = 5011
|
ErrUpgradeInsufficientResources = 5011
|
||||||
ErrSendShipHasNoDrives = 5012
|
ErrSendShipHasNoDrives = 5012
|
||||||
ErrSendUnreachableDestination = 5013
|
ErrSendUnreachableDestination = 5013
|
||||||
|
ErrRaceExinct = 5014
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -141,7 +142,7 @@ func GenericErrorText(code int) string {
|
|||||||
case ErrBeakGroupNumberNotEnough:
|
case ErrBeakGroupNumberNotEnough:
|
||||||
return "Not enough ships in the group to make a separate group"
|
return "Not enough ships in the group to make a separate group"
|
||||||
case ErrShipsBusy:
|
case ErrShipsBusy:
|
||||||
return "Ships currently not in orbit or free to use"
|
return "Ship(s) are'n free to use"
|
||||||
case ErrShipsNotOnSamePlanet:
|
case ErrShipsNotOnSamePlanet:
|
||||||
return "Ships not on the same planet"
|
return "Ships not on the same planet"
|
||||||
case ErrGiveawayGroupShipsTypeNotEqual:
|
case ErrGiveawayGroupShipsTypeNotEqual:
|
||||||
@@ -166,6 +167,8 @@ func GenericErrorText(code int) string {
|
|||||||
return "One or more ships are not equipped with hyperdrive and cannot be moved"
|
return "One or more ships are not equipped with hyperdrive and cannot be moved"
|
||||||
case ErrSendUnreachableDestination:
|
case ErrSendUnreachableDestination:
|
||||||
return "Destination planet is too far for current Drive level"
|
return "Destination planet is too far for current Drive level"
|
||||||
|
case ErrRaceExinct:
|
||||||
|
return "Race is extinct"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("Undescribed error with code %d", code)
|
return fmt.Sprintf("Undescribed error with code %d", code)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package error
|
package error
|
||||||
|
|
||||||
|
func NewRaceExinctError(arg ...any) error {
|
||||||
|
return newGenericError(ErrRaceExinct, arg...)
|
||||||
|
}
|
||||||
|
|
||||||
func NewGameNotInitializedError(arg ...any) error {
|
func NewGameNotInitializedError(arg ...any) error {
|
||||||
return newGenericError(ErrGameNotInitialized, arg...)
|
return newGenericError(ErrGameNotInitialized, arg...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ func TestCreateShipType(t *testing.T) {
|
|||||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputUnknownRace))
|
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
err = game.CreateShipType(p, race, " "+typeName+" ", 1, 0, 0, 0, 0)
|
err = game.CreateShipType(p, race, " "+typeName+" ", 1, 0, 0, 0, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
st, err := ctrl().ShipTypes(race)
|
st := ctrl().Cache.ShipTypes(1)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, st, 1)
|
assert.Len(t, st, 1)
|
||||||
assert.Equal(t, st[0].Name, typeName)
|
assert.Equal(t, st[0].Name, typeName)
|
||||||
assert.Equal(t, st[0].Drive.F(), 1.)
|
assert.Equal(t, st[0].Drive.F(), 1.)
|
||||||
@@ -36,8 +35,7 @@ func TestCreateShipType(t *testing.T) {
|
|||||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputUnknownRace))
|
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputUnknownRace))
|
||||||
err = game.DeleteShipType(p, race, typeName)
|
err = game.DeleteShipType(p, race, typeName)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
st, err = ctrl().ShipTypes(race)
|
st = ctrl().Cache.ShipTypes(1)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, st, 0)
|
assert.Len(t, st, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -96,7 +94,7 @@ func TestCreateShipTypeValidation(t *testing.T) {
|
|||||||
|
|
||||||
func TestMergeShipType(t *testing.T) {
|
func TestMergeShipType(t *testing.T) {
|
||||||
race := "race_01"
|
race := "race_01"
|
||||||
c(t, func(p func(*controller.Param), ctl func() *controller.Controller) {
|
c(t, func(p func(*controller.Param), ctrl func() *controller.Controller) {
|
||||||
err := game.CreateShipType(p, race, "Drone", 1, 0, 0, 0, 0)
|
err := game.CreateShipType(p, race, "Drone", 1, 0, 0, 0, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = game.CreateShipType(p, race, "Spy", 1, 0, 0, 0, 0)
|
err = game.CreateShipType(p, race, "Spy", 1, 0, 0, 0, 0)
|
||||||
@@ -109,8 +107,7 @@ func TestMergeShipType(t *testing.T) {
|
|||||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityNotExists))
|
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityNotExists))
|
||||||
err = game.MergeShipType(p, race, "Spy", "Drone")
|
err = game.MergeShipType(p, race, "Spy", "Drone")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
st, err := ctl().ShipTypes(race)
|
st := ctrl().Cache.ShipTypes(1)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, st, 2)
|
assert.Len(t, st, 2)
|
||||||
err = game.MergeShipType(p, race, "Drone", "Cruiser")
|
err = game.MergeShipType(p, race, "Drone", "Cruiser")
|
||||||
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrMergeShipTypeNotEqual))
|
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrMergeShipTypeNotEqual))
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const (
|
|||||||
StateLaunched ShipGroupState = "Launched"
|
StateLaunched ShipGroupState = "Launched"
|
||||||
StateInSpace ShipGroupState = "In_Space"
|
StateInSpace ShipGroupState = "In_Space"
|
||||||
StateUpgrade ShipGroupState = "Upgrade"
|
StateUpgrade ShipGroupState = "Upgrade"
|
||||||
StateTransfer ShipGroupState = "Transfer_Status"
|
StateTransfer ShipGroupState = "Transfer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sgs ShipGroupState) String() string {
|
func (sgs ShipGroupState) String() string {
|
||||||
@@ -104,17 +104,18 @@ func (t Tech) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ShipGroup struct {
|
type ShipGroup struct {
|
||||||
Index uint `json:"index"` // FIXME: use UUID for Group Index (ordered)
|
Index uint `json:"index"` // FIXME: use UUID for Group Index (ordered)
|
||||||
OwnerID uuid.UUID `json:"ownerId"` // Race link
|
OwnerID uuid.UUID `json:"ownerId"` // Race link
|
||||||
TypeID uuid.UUID `json:"typeId"` // ShipType link
|
TypeID uuid.UUID `json:"typeId"` // ShipType link
|
||||||
FleetID *uuid.UUID `json:"fleetId,omitempty"` // Fleet link
|
FleetID *uuid.UUID `json:"fleetId,omitempty"` // Fleet link
|
||||||
Number uint `json:"number"` // Number (quantity) ships of specific ShipType
|
Number uint `json:"number"` // Number (quantity) ships of specific ShipType
|
||||||
CargoType *CargoType `json:"loadType,omitempty"` //
|
CargoType *CargoType `json:"loadType,omitempty"` //
|
||||||
Load Float `json:"load"` // Cargo loaded - "Масса груза"
|
Load Float `json:"load"` // Cargo loaded - "Масса груза"
|
||||||
Tech TechSet `json:"tech"` //
|
Tech TechSet `json:"tech"` //
|
||||||
Destination uint `json:"destination"` // TODO: TEST: Destination, Origin, Range
|
Destination uint `json:"destination"` // TODO: TEST: Destination, Origin, Range
|
||||||
StateInSpace *InSpace `json:"stateInSpace,omitempty"` //
|
StateInSpace *InSpace `json:"inSpace,omitempty"` //
|
||||||
StateUpgrade *InUpgrade `json:"stateUpgrade,omitempty"` //
|
StateUpgrade *InUpgrade `json:"upgrade,omitempty"` //
|
||||||
|
StateTransfer bool `json:"transfer,omitempty"` //
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sg ShipGroup) TechLevel(t Tech) Float {
|
func (sg ShipGroup) TechLevel(t Tech) Float {
|
||||||
@@ -134,6 +135,9 @@ func (sg ShipGroup) State() ShipGroupState {
|
|||||||
if sg.StateInSpace.Range > 0 {
|
if sg.StateInSpace.Range > 0 {
|
||||||
return StateInSpace
|
return StateInSpace
|
||||||
}
|
}
|
||||||
|
if sg.StateTransfer {
|
||||||
|
return StateTransfer
|
||||||
|
}
|
||||||
return StateLaunched
|
return StateLaunched
|
||||||
case sg.StateUpgrade != nil && sg.StateInSpace == nil:
|
case sg.StateUpgrade != nil && sg.StateInSpace == nil:
|
||||||
return StateUpgrade
|
return StateUpgrade
|
||||||
|
|||||||
@@ -38,9 +38,16 @@ func (p *Planet) Free() {
|
|||||||
p.Owner = nil
|
p.Owner = nil
|
||||||
p.Production = ProductionNone.AsType(uuid.Nil)
|
p.Production = ProductionNone.AsType(uuid.Nil)
|
||||||
p.Colonists = 0.
|
p.Colonists = 0.
|
||||||
|
p.Population = 0.
|
||||||
clear(p.Route)
|
clear(p.Route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Planet) Wipe() {
|
||||||
|
p.Free()
|
||||||
|
p.Industry = 0
|
||||||
|
p.Capital = 0
|
||||||
|
}
|
||||||
|
|
||||||
func (p Planet) Owned() bool {
|
func (p Planet) Owned() bool {
|
||||||
return p.Owner != nil && *p.Owner != uuid.Nil
|
return p.Owner != nil && *p.Owner != uuid.Nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import "github.com/google/uuid"
|
|||||||
type Race struct {
|
type Race struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
TTL uint `json:"ttl"`
|
||||||
Extinct bool `json:"extinct"`
|
Extinct bool `json:"extinct"`
|
||||||
Votes Float `json:"votes"`
|
Votes Float `json:"votes"`
|
||||||
VoteFor uuid.UUID `json:"voteFor"`
|
VoteFor uuid.UUID `json:"voteFor"`
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ type Player struct {
|
|||||||
Planets uint16 `json:"planets"`
|
Planets uint16 `json:"planets"`
|
||||||
Relation string `json:"relation"`
|
Relation string `json:"relation"`
|
||||||
Votes Float `json:"votes"`
|
Votes Float `json:"votes"`
|
||||||
|
Extinct bool `json:"extinct"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Report) MarshalBinary() (data []byte, err error) {
|
func (r Report) MarshalBinary() (data []byte, err error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user