cmd: create/delete science

This commit is contained in:
Ilia Denisov
2025-10-01 14:30:36 +03:00
parent bcab29a47f
commit 2295840efe
9 changed files with 385 additions and 155 deletions
+14 -8
View File
@@ -12,6 +12,7 @@ const (
ErrDeleteShipTypeExistingGroup = 5000 ErrDeleteShipTypeExistingGroup = 5000
ErrDeleteShipTypePlanetProduction = 5001 ErrDeleteShipTypePlanetProduction = 5001
ErrDeleteSciencePlanetProduction = 5002
) )
const ( const (
@@ -20,13 +21,14 @@ const (
ErrInputEntityTypeNameInvalid ErrInputEntityTypeNameInvalid
ErrInputEntityTypeNameDuplicate ErrInputEntityTypeNameDuplicate
ErrInputEntityTypeNameNotExists ErrInputEntityTypeNameNotExists
ErrInputShipTypeDriveValue ErrInputDriveValue
ErrInputShipTypeWeaponsValue ErrInputWeaponsValue
ErrInputShipTypeShieldsValue ErrInputShieldsValue
ErrInputShipTypeCargoValue ErrInputCargoValue
ErrInputShipTypeArmamentValue ErrInputShipTypeArmamentValue
ErrInputShipTypeWeaponsAndArmamentValue ErrInputShipTypeWeaponsAndArmamentValue
ErrInputShipTypeZeroValues ErrInputShipTypeZeroValues
ErrInputScienceSumValues
) )
func GenericErrorText(code int) string { func GenericErrorText(code int) string {
@@ -47,13 +49,13 @@ func GenericErrorText(code int) string {
return "Name already exists" return "Name already exists"
case ErrInputEntityTypeNameNotExists: case ErrInputEntityTypeNameNotExists:
return "Name not exists" return "Name not exists"
case ErrInputShipTypeDriveValue: case ErrInputDriveValue:
return "Invalid Drive value" return "Invalid Drive value"
case ErrInputShipTypeWeaponsValue: case ErrInputWeaponsValue:
return "Invalid Weapons value" return "Invalid Weapons value"
case ErrInputShipTypeShieldsValue: case ErrInputShieldsValue:
return "Invalid Shields value" return "Invalid Shields value"
case ErrInputShipTypeCargoValue: case ErrInputCargoValue:
return "Invalid Cargo value" return "Invalid Cargo value"
case ErrInputShipTypeArmamentValue: case ErrInputShipTypeArmamentValue:
return "Invalid Armament value" return "Invalid Armament value"
@@ -65,6 +67,10 @@ func GenericErrorText(code int) string {
return "Ship type exists in a Group" return "Ship type exists in a Group"
case ErrDeleteShipTypePlanetProduction: case ErrDeleteShipTypePlanetProduction:
return "Ship type in production on the Planet" return "Ship type in production on the Planet"
case ErrDeleteSciencePlanetProduction:
return "Science in production on the Planet"
case ErrInputScienceSumValues:
return "Science proportions sum should be equal 1"
default: default:
return fmt.Sprintf("Undescribed error with code %d", code) return fmt.Sprintf("Undescribed error with code %d", code)
} }
+12 -8
View File
@@ -20,20 +20,20 @@ func NewEntityTypeNameNotExistsError(arg ...any) error {
return newGenericError(ErrInputEntityTypeNameNotExists, arg...) return newGenericError(ErrInputEntityTypeNameNotExists, arg...)
} }
func NewShipTypeDriveValueError(arg ...any) error { func NewDriveValueError(arg ...any) error {
return newGenericError(ErrInputShipTypeDriveValue, arg...) return newGenericError(ErrInputDriveValue, arg...)
} }
func NewShipTypeWeaponsValueError(arg ...any) error { func NewWeaponsValueError(arg ...any) error {
return newGenericError(ErrInputShipTypeWeaponsValue, arg...) return newGenericError(ErrInputWeaponsValue, arg...)
} }
func NewShipTypeShieldsValueError(arg ...any) error { func NewShieldsValueError(arg ...any) error {
return newGenericError(ErrInputShipTypeShieldsValue, arg...) return newGenericError(ErrInputShieldsValue, arg...)
} }
func NewShipTypeCargoValueError(arg ...any) error { func NewCargoValueError(arg ...any) error {
return newGenericError(ErrInputShipTypeCargoValue, arg...) return newGenericError(ErrInputCargoValue, arg...)
} }
func NewShipTypeArmamentValueError(arg ...any) error { func NewShipTypeArmamentValueError(arg ...any) error {
@@ -47,3 +47,7 @@ func NewShipTypeArmamentAndWeaponsValueError(arg ...any) error {
func NewShipTypeShipTypeZeroValuesError(arg ...any) error { func NewShipTypeShipTypeZeroValuesError(arg ...any) error {
return newGenericError(ErrInputShipTypeZeroValues, arg...) return newGenericError(ErrInputShipTypeZeroValues, arg...)
} }
func NewScienceSumValuesError(arg ...any) error {
return newGenericError(ErrInputScienceSumValues, arg...)
}
+4
View File
@@ -11,3 +11,7 @@ func NewDeleteShipTypeExistingGroupError(arg ...any) error {
func NewDeleteShipTypePlanetProductionError(arg ...any) error { func NewDeleteShipTypePlanetProductionError(arg ...any) error {
return newGenericError(ErrDeleteShipTypePlanetProduction, arg...) return newGenericError(ErrDeleteShipTypePlanetProduction, arg...)
} }
func NewDeleteSciencePlanetProductionError(arg ...any) error {
return newGenericError(ErrDeleteSciencePlanetProduction, arg...)
}
+35
View File
@@ -0,0 +1,35 @@
package game
import "github.com/iliadenisov/galaxy/pkg/model/game"
func CreateScience(configure func(*Param), race, typeName string, drive, weapons, shields, cargo float64) (err error) {
control(configure, func(c *ctrl) {
c.execute(func(r Repo, g game.Game) {
err = createScience(r, g, race, typeName, drive, weapons, shields, cargo)
})
})
return
}
func createScience(r Repo, g game.Game, race, typeName string, d, w, s, c float64) error {
if err := g.CreateScience(race, typeName, d, w, s, c); err != nil {
return err
}
return r.SaveState(g)
}
func DeleteScience(configure func(*Param), race, typeName string) (err error) {
control(configure, func(c *ctrl) {
c.execute(func(r Repo, g game.Game) {
err = deleteScience(r, g, race, typeName)
})
})
return
}
func deleteScience(r Repo, g game.Game, race, typeName string) error {
if err := g.DeleteScience(race, typeName); err != nil {
return err
}
return r.SaveState(g)
}
+83
View File
@@ -0,0 +1,83 @@
package game_test
import (
"strconv"
"testing"
e "github.com/iliadenisov/galaxy/pkg/error"
"github.com/iliadenisov/galaxy/pkg/game"
mg "github.com/iliadenisov/galaxy/pkg/model/game"
"github.com/stretchr/testify/assert"
)
func TestCreateScience(t *testing.T) {
race := "race_01"
typeName := "First Step"
g(t, func(p func(*game.Param), g func() mg.Game) {
err := game.DeleteScience(p, race, typeName)
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityTypeNameNotExists))
err = game.CreateScience(p, race, " "+typeName+" ", 1, 0, 0, 0)
assert.NoError(t, err)
sc, err := g().Sciences(race)
assert.NoError(t, err)
assert.Len(t, sc, 1)
assert.Equal(t, sc[0].Name, typeName)
assert.Equal(t, sc[0].Drive, 1.)
assert.Equal(t, sc[0].Weapons, 0.)
assert.Equal(t, sc[0].Shields, 0.)
assert.Equal(t, sc[0].Cargo, 0.)
// TODO: test with existing ship group
err = game.DeleteScience(p, race, typeName)
assert.NoError(t, err)
sc, err = g().Sciences(race)
assert.NoError(t, err)
assert.Len(t, sc, 0)
})
}
func TestCreateScienceValidation(t *testing.T) {
race := "race_01"
typeName := "First Step"
type tc struct {
name string
d, w, s, c float64
err string
}
table := []tc{
// correct values
{typeName, 1, 0, 0, 0, ""},
{typeName, 0.5, 0.5, 0, 0, ""},
{typeName, 0.25, 0.25, 0.25, 0.25, ""},
{typeName, 0.33, 0.33, 0.34, 0, ""},
{typeName, 0, 0, 0.99, 0.01, ""},
// incorrect values...
{"", 1, 0, 0, 0, e.GenericErrorText(e.ErrInputEntityTypeNameInvalid)},
{" ", 1, 0, 0, 0, e.GenericErrorText(e.ErrInputEntityTypeNameInvalid)},
{typeName, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputScienceSumValues)},
// drive
{typeName, -1, 0, 0, 0, e.GenericErrorText(e.ErrInputDriveValue)},
{typeName, -1, 2, 0, 0, e.GenericErrorText(e.ErrInputDriveValue)},
// weapons
{typeName, 0, -1, 0, 0, e.GenericErrorText(e.ErrInputWeaponsValue)},
{typeName, 2, -1, 0, 0, e.GenericErrorText(e.ErrInputWeaponsValue)},
// shields
{typeName, 0, 0, -1, 0, e.GenericErrorText(e.ErrInputShieldsValue)},
{typeName, 0.5, 0.5, -1, 0.5, e.GenericErrorText(e.ErrInputShieldsValue)},
// cargo
{typeName, 0, 0, 0, -1, e.GenericErrorText(e.ErrInputCargoValue)},
{typeName, 0, 1, 1, -1, e.GenericErrorText(e.ErrInputCargoValue)},
}
g(t, func(p func(*game.Param), g func() mg.Game) {
for i, tc := range table {
if tc.err == "" {
err := game.CreateScience(p, race, tc.name+strconv.Itoa(i), tc.d, tc.w, tc.s, tc.c)
assert.NoError(t, err)
err = game.CreateScience(p, race, tc.name+strconv.Itoa(i), tc.d, tc.w, tc.s, tc.c)
assert.ErrorContains(t, err, e.GenericErrorText(e.ErrInputEntityTypeNameDuplicate))
} else {
err := game.CreateScience(p, race, tc.name, tc.d, tc.w, tc.s, tc.c)
assert.ErrorContains(t, err, tc.err)
}
}
})
}
+9 -9
View File
@@ -21,7 +21,7 @@ func TestCreateShipType(t *testing.T) {
st, err := g().ShipTypes(race) st, err := g().ShipTypes(race)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, st, 1) assert.Len(t, st, 1)
assert.Equal(t, st[0].Name, "Drone") assert.Equal(t, st[0].Name, typeName)
assert.Equal(t, st[0].Drive, 1.) assert.Equal(t, st[0].Drive, 1.)
assert.Equal(t, st[0].Weapons, 0.) assert.Equal(t, st[0].Weapons, 0.)
assert.Equal(t, st[0].Shields, 0.) assert.Equal(t, st[0].Shields, 0.)
@@ -57,17 +57,17 @@ func TestCreateShipTypeValidation(t *testing.T) {
{" ", 1, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputEntityTypeNameInvalid)}, {" ", 1, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputEntityTypeNameInvalid)},
{typeName, 0, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeZeroValues)}, {typeName, 0, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeZeroValues)},
// drive // drive
{typeName, -1, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeDriveValue)}, {typeName, -1, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputDriveValue)},
{typeName, 0.5, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeDriveValue)}, {typeName, 0.5, 0, 0, 0, 0, e.GenericErrorText(e.ErrInputDriveValue)},
// weapons // weapons
{typeName, 0, -1, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeWeaponsValue)}, {typeName, 0, -1, 0, 0, 0, e.GenericErrorText(e.ErrInputWeaponsValue)},
{typeName, 0, 0.5, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeWeaponsValue)}, {typeName, 0, 0.5, 0, 0, 0, e.GenericErrorText(e.ErrInputWeaponsValue)},
// shields // shields
{typeName, 0, 0, -1, 0, 0, e.GenericErrorText(e.ErrInputShipTypeShieldsValue)}, {typeName, 0, 0, -1, 0, 0, e.GenericErrorText(e.ErrInputShieldsValue)},
{typeName, 0, 0, 0.5, 0, 0, e.GenericErrorText(e.ErrInputShipTypeShieldsValue)}, {typeName, 0, 0, 0.5, 0, 0, e.GenericErrorText(e.ErrInputShieldsValue)},
// cargo // cargo
{typeName, 0, 0, 0, -1, 0, e.GenericErrorText(e.ErrInputShipTypeCargoValue)}, {typeName, 0, 0, 0, -1, 0, e.GenericErrorText(e.ErrInputCargoValue)},
{typeName, 0, 0, 0, 0.5, 0, e.GenericErrorText(e.ErrInputShipTypeCargoValue)}, {typeName, 0, 0, 0, 0.5, 0, e.GenericErrorText(e.ErrInputCargoValue)},
// armament (and weapons) // armament (and weapons)
{typeName, 0, 0, 0, 0, -1, e.GenericErrorText(e.ErrInputShipTypeArmamentValue)}, {typeName, 0, 0, 0, 0, -1, e.GenericErrorText(e.ErrInputShipTypeArmamentValue)},
{typeName, 0, 1, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeWeaponsAndArmamentValue)}, {typeName, 0, 1, 0, 0, 0, e.GenericErrorText(e.ErrInputShipTypeWeaponsAndArmamentValue)},
+104 -1
View File
@@ -1,6 +1,9 @@
package game package game
import "github.com/google/uuid" import (
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/pkg/error"
)
type Science struct { type Science struct {
ID uuid.UUID `json:"id"` ID uuid.UUID `json:"id"`
@@ -19,3 +22,103 @@ type ScienceReport struct {
Shields float64 `json:"shields"` Shields float64 `json:"shields"`
Cargo float64 `json:"cargo"` Cargo float64 `json:"cargo"`
} }
func (g Game) Sciences(raceName string) ([]Science, error) {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return nil, err
}
return g.sciencesInternal(raceID)
}
func (g Game) sciencesInternal(race uuid.UUID) ([]Science, error) {
for r := range g.Race {
if g.Race[r].ID == race {
return g.Race[r].Sciences, nil
}
}
return nil, e.NewGameStateError("Sciences: race %v not found", race)
}
func (g Game) DeleteScience(raceName, typeName string) error {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
return g.deleteScienceInternal(raceID, typeName)
}
func (g Game) deleteScienceInternal(race uuid.UUID, name string) error {
for r := range g.Race {
if g.Race[r].ID == race {
for sc := range g.Race[r].Sciences {
if g.Race[r].Sciences[sc].Name == name {
for pl := range g.Map.Planet {
if g.Map.Planet[pl].Production.Production == ResearchScience &&
g.Map.Planet[pl].Production.SubjectID != nil &&
*g.Map.Planet[pl].Production.SubjectID == g.Race[r].Sciences[sc].ID {
return e.NewDeleteSciencePlanetProductionError(g.Map.Planet[pl].Name)
}
}
g.Race[r].Sciences = append(g.Race[r].Sciences[:sc], g.Race[r].Sciences[sc+1:]...)
return nil
}
}
return e.NewEntityTypeNameNotExistsError("science %w", name)
}
}
return e.NewGameStateError("DeleteScience: race %v not found", race)
}
func (g Game) CreateScience(raceName, typeName string, d, w, s, c float64) error {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
return g.createScienceInternal(raceID, typeName, d, w, s, c)
}
func (g Game) createScienceInternal(race uuid.UUID, n string, d, w, s, c float64) error {
name, ok := validateTypeName(n)
if !ok {
return e.NewEntityTypeNameValidationError("%q", name)
}
if d < 0 {
return e.NewDriveValueError(d)
}
if w < 0 {
return e.NewWeaponsValueError(w)
}
if s < 0 {
return e.NewShieldsValueError(s)
}
if c < 0 {
return e.NewCargoValueError(c)
}
sum := d + w + s + c
if sum != 1 {
return e.NewScienceSumValuesError("D=%f W=%f S=%f C=%f sum=%f", d, w, s, c, sum)
}
for r := range g.Race {
if g.Race[r].ID == race {
for sc := range g.Race[r].Sciences {
if g.Race[r].Sciences[sc].Name == name {
return e.NewEntityTypeNameDuplicateError("science %w", g.Race[r].Sciences[sc].Name)
}
}
id := uuid.New()
g.Race[r].Sciences = append(g.Race[r].Sciences, Science{
ID: id,
ScienceReport: ScienceReport{
Name: name,
Drive: d,
Weapons: w,
Shields: s,
Cargo: c,
},
})
return nil
}
}
return e.NewGameStateError("CreateScience: race %v not found", race)
}
+124
View File
@@ -4,6 +4,7 @@ import (
"math" "math"
"github.com/google/uuid" "github.com/google/uuid"
e "github.com/iliadenisov/galaxy/pkg/error"
"github.com/iliadenisov/galaxy/pkg/number" "github.com/iliadenisov/galaxy/pkg/number"
) )
@@ -128,3 +129,126 @@ func (fl Fleet) Speed() float64 {
} }
return result return result
} }
func (g Game) ShipTypes(raceName string) ([]ShipType, error) {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return nil, err
}
return g.shipTypesInternal(raceID)
}
func (g Game) shipTypesInternal(race uuid.UUID) ([]ShipType, error) {
for r := range g.Race {
if g.Race[r].ID == race {
return g.Race[r].ShipTypes, nil
}
}
return nil, e.NewGameStateError("ShipTypes: race %v not found", race)
}
func (g Game) DeleteShipType(raceName, typeName string) error {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
return g.deleteShipTypeInternal(raceID, typeName)
}
func (g Game) deleteShipTypeInternal(race uuid.UUID, name string) error {
for r := range g.Race {
if g.Race[r].ID == race {
for st := range g.Race[r].ShipTypes {
if g.Race[r].ShipTypes[st].Name == name {
for sg := range g.Race[r].ShipGroups {
if g.Race[r].ShipGroups[sg].TypeID == g.Race[r].ShipTypes[st].ID {
return e.NewDeleteShipTypeExistingGroupError(g.Race[r].ShipGroups[sg].Number)
}
}
for pl := range g.Map.Planet {
if g.Map.Planet[pl].Owner == race &&
g.Map.Planet[pl].Production.Production == ProductionShip &&
g.Map.Planet[pl].Production.SubjectID != nil &&
g.Race[r].ShipTypes[st].ID == *g.Map.Planet[pl].Production.SubjectID {
return e.NewDeleteShipTypePlanetProductionError(g.Map.Planet[pl].Name)
}
}
g.Race[r].ShipTypes = append(g.Race[r].ShipTypes[:st], g.Race[r].ShipTypes[st+1:]...)
return nil
}
}
return e.NewEntityTypeNameNotExistsError("ship type %w", name)
}
}
return e.NewGameStateError("DeleteShipType: race %v not found", race)
}
func (g Game) CreateShipType(raceName, typeName string, d, w, s, c float64, a int) error {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
return g.createShipTypeInternal(raceID, typeName, d, w, s, c, a)
}
func (g Game) createShipTypeInternal(race uuid.UUID, n string, d, w, s, c float64, a int) error {
if err := checkShipTypeValues(d, w, s, c, a); err != nil {
return err
}
name, ok := validateTypeName(n)
if !ok {
return e.NewEntityTypeNameValidationError("%q", name)
}
for r := range g.Race {
if g.Race[r].ID == race {
for st := range g.Race[r].ShipTypes {
if g.Race[r].ShipTypes[st].Name == name {
return e.NewEntityTypeNameDuplicateError("ship type %w", g.Race[r].ShipTypes[st].Name)
}
}
id := uuid.New()
g.Race[r].ShipTypes = append(g.Race[r].ShipTypes, ShipType{
ID: id,
ShipTypeReport: ShipTypeReport{
Name: name,
Drive: d,
Weapons: w,
Shields: s,
Cargo: c,
Armament: uint(a),
},
})
return nil
}
}
return e.NewGameStateError("CreateShipType: race %v not found", race)
}
func checkShipTypeValues(d, w, s, c float64, a int) error {
if !checkShipTypeValueDWSC(d) {
return e.NewDriveValueError(d)
}
if !checkShipTypeValueDWSC(w) {
return e.NewWeaponsValueError(w)
}
if !checkShipTypeValueDWSC(s) {
return e.NewShieldsValueError(s)
}
if !checkShipTypeValueDWSC(c) {
return e.NewCargoValueError(s)
}
if a < 0 {
return e.NewShipTypeArmamentValueError(a)
}
if (w == 0 && a > 0) || (a == 0 && w > 0) {
return e.NewShipTypeArmamentAndWeaponsValueError("A=%d W=%.0f", a, w)
}
if d == 0 && w == 0 && s == 0 && c == 0 && a == 0 {
return e.NewShipTypeShipTypeZeroValuesError()
}
return nil
}
func checkShipTypeValueDWSC(v float64) bool {
return v == 0 || v >= 1
}
-129
View File
@@ -1,129 +0,0 @@
package game
import (
"github.com/google/uuid"
e "github.com/iliadenisov/galaxy/pkg/error"
)
func (g Game) ShipTypes(raceName string) ([]ShipType, error) {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return nil, err
}
return g.shipTypesInternal(raceID)
}
func (g Game) shipTypesInternal(race uuid.UUID) ([]ShipType, error) {
for r := range g.Race {
if g.Race[r].ID == race {
return g.Race[r].ShipTypes, nil
}
}
return nil, e.NewGameStateError("ShipTypes: race %v not found", race)
}
func (g Game) DeleteShipType(raceName, typeName string) error {
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
return g.deleteShipTypeInternal(raceID, typeName)
}
func (g Game) deleteShipTypeInternal(race uuid.UUID, name string) error {
for r := range g.Race {
if g.Race[r].ID == race {
for st := range g.Race[r].ShipTypes {
if g.Race[r].ShipTypes[st].Name == name {
for sg := range g.Race[r].ShipGroups {
if g.Race[r].ShipGroups[sg].TypeID == g.Race[r].ShipTypes[st].ID {
return e.NewDeleteShipTypeExistingGroupError(g.Race[r].ShipGroups[sg].Number)
}
}
for pl := range g.Map.Planet {
if g.Map.Planet[pl].Owner == race &&
g.Map.Planet[pl].Production.Production == ProductionShip &&
g.Map.Planet[pl].Production.SubjectID != nil &&
g.Race[r].ShipTypes[st].ID == *g.Map.Planet[pl].Production.SubjectID {
return e.NewDeleteShipTypePlanetProductionError(g.Map.Planet[pl].Name)
}
}
g.Race[r].ShipTypes = append(g.Race[r].ShipTypes[:st], g.Race[r].ShipTypes[st+1:]...)
return nil
}
}
return e.NewEntityTypeNameNotExistsError("ship type %w", name)
}
}
return e.NewGameStateError("DeleteShipType: race %v not found", race)
}
func (g Game) CreateShipType(raceName, typeName string, d, w, s, c float64, a int) error {
if err := checkShipTypeValues(d, w, s, c, a); err != nil {
return err
}
raceID, err := g.hostRaceID(raceName)
if err != nil {
return err
}
tn, ok := validateTypeName(typeName)
if !ok {
return e.NewEntityTypeNameValidationError("%q", tn)
}
return g.createShipTypeInternal(raceID, tn, d, w, s, c, a)
}
func (g Game) createShipTypeInternal(race uuid.UUID, name string, d, w, s, c float64, a int) error {
for r := range g.Race {
if g.Race[r].ID == race {
for st := range g.Race[r].ShipTypes {
if g.Race[r].ShipTypes[st].Name == name {
return e.NewEntityTypeNameDuplicateError("ship type %w", g.Race[r].ShipTypes[st].Name)
}
}
id := uuid.New()
g.Race[r].ShipTypes = append(g.Race[r].ShipTypes, ShipType{
ID: id,
ShipTypeReport: ShipTypeReport{
Name: name,
Drive: d,
Weapons: w,
Shields: s,
Cargo: c,
Armament: uint(a),
},
})
return nil
}
}
return e.NewGameStateError("CreateShipType: race %v not found", race)
}
func checkShipTypeValues(d, w, s, c float64, a int) error {
if !checkShipTypeValueDWSC(d) {
return e.NewShipTypeDriveValueError(d)
}
if !checkShipTypeValueDWSC(w) {
return e.NewShipTypeWeaponsValueError(w)
}
if !checkShipTypeValueDWSC(s) {
return e.NewShipTypeShieldsValueError(s)
}
if !checkShipTypeValueDWSC(c) {
return e.NewShipTypeCargoValueError(s)
}
if a < 0 {
return e.NewShipTypeArmamentValueError(a)
}
if (w == 0 && a > 0) || (a == 0 && w > 0) {
return e.NewShipTypeArmamentAndWeaponsValueError("A=%d W=%.0f", a, w)
}
if d == 0 && w == 0 && s == 0 && c == 0 && a == 0 {
return e.NewShipTypeShipTypeZeroValuesError()
}
return nil
}
func checkShipTypeValueDWSC(v float64) bool {
return v == 0 || v >= 1
}