cmd: upgrade group
This commit is contained in:
+115
-39
@@ -1,6 +1,7 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"maps"
|
||||
"math"
|
||||
@@ -35,50 +36,128 @@ func (ct CargoType) String() string {
|
||||
return string(ct)
|
||||
}
|
||||
|
||||
type ShipGroupState string
|
||||
|
||||
const (
|
||||
StateInOrbit ShipGroupState = "In_Orbit"
|
||||
StateLaunched ShipGroupState = "Launched"
|
||||
StateInSpace ShipGroupState = "In_Space"
|
||||
StateUpgrade ShipGroupState = "Upgrade"
|
||||
StateTransfer ShipGroupState = "Transfer_Status"
|
||||
)
|
||||
|
||||
type InSpace struct {
|
||||
Origin uint `json:"origin"`
|
||||
// zero is for Launched status
|
||||
Range float64 `json:"range"`
|
||||
}
|
||||
|
||||
type InUpgrade struct {
|
||||
UpgradeTech []UpgradePreference `json:"preference"`
|
||||
}
|
||||
|
||||
func (iu InUpgrade) Cost() float64 {
|
||||
var sum float64
|
||||
for i := range iu.UpgradeTech {
|
||||
sum += iu.UpgradeTech[i].Cost
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (iu InUpgrade) TechCost(t Tech) float64 {
|
||||
for i := range iu.UpgradeTech {
|
||||
if iu.UpgradeTech[i].Tech == t {
|
||||
return iu.UpgradeTech[i].Cost
|
||||
}
|
||||
}
|
||||
return 0.
|
||||
}
|
||||
|
||||
type UpgradePreference struct {
|
||||
Tech Tech `json:"tech"`
|
||||
Level float64 `json:"level"`
|
||||
Cost float64 `json:"cost"`
|
||||
}
|
||||
|
||||
type Tech string
|
||||
|
||||
const (
|
||||
TechAll Tech = "ALL"
|
||||
TechDrive Tech = "DRIVE"
|
||||
TechWeapons Tech = "WEAPONS"
|
||||
TechShields Tech = "SHIELDS"
|
||||
TechCargo Tech = "CARGO"
|
||||
)
|
||||
|
||||
func (t Tech) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
type ShipGroup struct {
|
||||
Index uint `json:"index"` // FIXME: use UUID for Group Index (ordered)
|
||||
OwnerID uuid.UUID `json:"ownerId"` // Race link
|
||||
TypeID uuid.UUID `json:"typeId"` // ShipType link
|
||||
FleetID *uuid.UUID `json:"fleetId,omitempty"` // Fleet link
|
||||
Number uint `json:"number"` // Number (quantity) ships of specific ShipType
|
||||
State string `json:"state"` // TODO: kinda enum: In_Orbit, In_Space, Transfer_State, Upgrade
|
||||
|
||||
CargoType *CargoType `json:"loadType,omitempty"`
|
||||
Load float64 `json:"load"` // Cargo loaded - "Масса груза"
|
||||
|
||||
Drive float64 `json:"drive"`
|
||||
Weapons float64 `json:"weapons"`
|
||||
Shields float64 `json:"shields"`
|
||||
Cargo float64 `json:"cargo"`
|
||||
Tech TechSet `json:"tech"`
|
||||
|
||||
// TODO: TEST: Destination, Origin, Range
|
||||
Destination uint `json:"destination"`
|
||||
Origin *uint `json:"origin,omitempty"`
|
||||
Range *float64 `json:"range,omitempty"`
|
||||
Destination uint `json:"destination"`
|
||||
StateInSpace *InSpace `json:"stateInSpace,omitempty"`
|
||||
StateUpgrade *InUpgrade `json:"stateUpgrade,omitempty"`
|
||||
}
|
||||
|
||||
func (sg ShipGroup) TechLevel(t Tech) float64 {
|
||||
return sg.Tech.Value(t)
|
||||
}
|
||||
|
||||
// TODO: refactor to separate method with *ShipGroup as parameter
|
||||
func (sg *ShipGroup) SetTechLevel(t Tech, v float64) {
|
||||
sg.Tech = sg.Tech.Set(t, v)
|
||||
}
|
||||
|
||||
func (sg ShipGroup) State() ShipGroupState {
|
||||
switch {
|
||||
case sg.StateInSpace == nil && sg.StateUpgrade == nil:
|
||||
return StateInOrbit
|
||||
case sg.StateInSpace != nil && sg.StateUpgrade == nil:
|
||||
if sg.StateInSpace.Range > 0 {
|
||||
return StateInSpace
|
||||
}
|
||||
return StateLaunched
|
||||
case sg.StateUpgrade != nil && sg.StateInSpace == nil:
|
||||
return StateUpgrade
|
||||
default:
|
||||
panic(fmt.Sprintf("ambigous group state: in_space=%#v upgrage=%#v", sg.StateInSpace, sg.StateUpgrade))
|
||||
}
|
||||
}
|
||||
|
||||
func (sg ShipGroup) Equal(other ShipGroup) bool {
|
||||
return sg.OwnerID == other.OwnerID &&
|
||||
sg.TypeID == other.TypeID &&
|
||||
sg.FleetID == other.FleetID &&
|
||||
sg.Drive == other.Drive &&
|
||||
sg.Weapons == other.Weapons &&
|
||||
sg.Shields == other.Shields &&
|
||||
sg.Cargo == other.Cargo &&
|
||||
sg.TechLevel(TechDrive) == other.TechLevel(TechDrive) &&
|
||||
sg.TechLevel(TechWeapons) == other.TechLevel(TechWeapons) &&
|
||||
sg.TechLevel(TechShields) == other.TechLevel(TechShields) &&
|
||||
sg.TechLevel(TechCargo) == other.TechLevel(TechCargo) &&
|
||||
sg.CargoType == other.CargoType &&
|
||||
sg.Load == other.Load &&
|
||||
sg.State == other.State
|
||||
sg.State() == other.State()
|
||||
}
|
||||
|
||||
// Грузоподъёмность
|
||||
func (sg ShipGroup) CargoCapacity(st *ShipType) float64 {
|
||||
return sg.Cargo * (st.Cargo + (st.Cargo*st.Cargo)/20) * float64(sg.Number)
|
||||
return sg.TechLevel(TechCargo) * (st.Cargo + (st.Cargo*st.Cargo)/20) * float64(sg.Number)
|
||||
}
|
||||
|
||||
// Масса перевозимого груза -
|
||||
// общее количество единиц груза, деленное на технологический уровень Грузоперевозок
|
||||
func (sg ShipGroup) CarryingMass() float64 {
|
||||
return sg.Load / sg.Cargo
|
||||
return sg.Load / sg.TechLevel(TechCargo)
|
||||
}
|
||||
|
||||
// Масса группы без учёта груза
|
||||
@@ -95,7 +174,7 @@ func (sg ShipGroup) FullMass(st *ShipType) float64 {
|
||||
// Эффективность двигателя -
|
||||
// равна мощности Двигателей, умноженной на технологический уровень блока Двигателей
|
||||
func (sg ShipGroup) DriveEffective(st *ShipType) float64 {
|
||||
return st.Drive * sg.Drive
|
||||
return st.Drive * sg.TechLevel(TechDrive)
|
||||
}
|
||||
|
||||
// Корабли перемещаются за один ход на количество световых лет, равное
|
||||
@@ -105,29 +184,29 @@ func (sg ShipGroup) Speed(st *ShipType) float64 {
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeDriveCost(st *ShipType, drive float64) float64 {
|
||||
return (1 - sg.Drive/drive) * 10 * st.Drive
|
||||
return (1 - sg.TechLevel(TechDrive)/drive) * 10 * st.Drive
|
||||
}
|
||||
|
||||
// TODO: test on other values
|
||||
func (sg ShipGroup) UpgradeWeaponsCost(st *ShipType, weapons float64) float64 {
|
||||
return (1 - sg.Weapons/weapons) * 10 * st.WeaponsMass()
|
||||
return (1 - sg.TechLevel(TechWeapons)/weapons) * 10 * st.WeaponsBlockMass()
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeShieldsCost(st *ShipType, shields float64) float64 {
|
||||
return (1 - sg.Shields/shields) * 10 * st.Shields
|
||||
return (1 - sg.TechLevel(TechShields)/shields) * 10 * st.Shields
|
||||
}
|
||||
|
||||
func (sg ShipGroup) UpgradeCargoCost(st *ShipType, cargo float64) float64 {
|
||||
return (1 - sg.Cargo/cargo) * 10 * st.Cargo
|
||||
return (1 - sg.TechLevel(TechCargo)/cargo) * 10 * st.Cargo
|
||||
}
|
||||
|
||||
// Мощность бомбардировки
|
||||
// TODO: maybe rounding must be done only for display?
|
||||
func (sg ShipGroup) BombingPower(st *ShipType) float64 {
|
||||
// return math.Sqrt(sg.Type.Weapons * sg.Weapons)
|
||||
result := (math.Sqrt(st.Weapons*sg.Weapons)/10. + 1.) *
|
||||
result := (math.Sqrt(st.Weapons*sg.TechLevel(TechWeapons))/10. + 1.) *
|
||||
st.Weapons *
|
||||
sg.Weapons *
|
||||
sg.TechLevel(TechWeapons) *
|
||||
float64(st.Armament) *
|
||||
float64(sg.Number)
|
||||
return number.Fixed3(result)
|
||||
@@ -173,7 +252,7 @@ func (g *Game) disassembleGroupInternal(ri int, groupIndex, quantity uint) error
|
||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
}
|
||||
|
||||
if g.ShipGroups[sgi].State != "In_Orbit" || g.ShipGroups[sgi].Origin != nil || g.ShipGroups[sgi].Range != nil {
|
||||
if g.ShipGroups[sgi].State() != StateInOrbit {
|
||||
return e.NewShipsBusyError()
|
||||
}
|
||||
|
||||
@@ -257,7 +336,7 @@ func (g *Game) unloadCargoInternal(ri int, groupIndex uint, ships uint, quantity
|
||||
if sgi < 0 {
|
||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
}
|
||||
if g.ShipGroups[sgi].State != "In_Orbit" || g.ShipGroups[sgi].Origin != nil || g.ShipGroups[sgi].Range != nil {
|
||||
if g.ShipGroups[sgi].State() != StateInOrbit {
|
||||
return e.NewShipsBusyError()
|
||||
}
|
||||
var sti int
|
||||
@@ -336,7 +415,7 @@ func (g *Game) loadCargoInternal(ri int, groupIndex uint, ct CargoType, ships ui
|
||||
if sgi < 0 {
|
||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
}
|
||||
if g.ShipGroups[sgi].State != "In_Orbit" || g.ShipGroups[sgi].Origin != nil || g.ShipGroups[sgi].Range != nil {
|
||||
if g.ShipGroups[sgi].State() != StateInOrbit {
|
||||
return e.NewShipsBusyError()
|
||||
}
|
||||
pl := slices.IndexFunc(g.Map.Planet, func(p Planet) bool { return p.Number == g.ShipGroups[sgi].Destination })
|
||||
@@ -464,19 +543,15 @@ func (g *Game) giveawayGroupInternal(ri, riAccept int, groupIndex, quantity uint
|
||||
OwnerID: g.Race[riAccept].ID,
|
||||
TypeID: g.Race[riAccept].ShipTypes[stAcc].ID,
|
||||
Number: uint(quantity),
|
||||
State: g.ShipGroups[sgi].State,
|
||||
|
||||
CargoType: g.ShipGroups[sgi].CargoType,
|
||||
Load: g.ShipGroups[sgi].Load,
|
||||
|
||||
Drive: g.ShipGroups[sgi].Drive,
|
||||
Weapons: g.ShipGroups[sgi].Weapons,
|
||||
Shields: g.ShipGroups[sgi].Shields,
|
||||
Cargo: g.ShipGroups[sgi].Cargo,
|
||||
Tech: maps.Clone(g.ShipGroups[sgi].Tech),
|
||||
|
||||
Destination: g.ShipGroups[sgi].Destination,
|
||||
Origin: g.ShipGroups[sgi].Origin,
|
||||
Range: g.ShipGroups[sgi].Range,
|
||||
Destination: g.ShipGroups[sgi].Destination,
|
||||
StateInSpace: g.ShipGroups[sgi].StateInSpace,
|
||||
StateUpgrade: g.ShipGroups[sgi].StateUpgrade,
|
||||
})
|
||||
|
||||
if quantity == 0 || quantity == g.ShipGroups[sgi].Number {
|
||||
@@ -503,7 +578,7 @@ func (g *Game) breakGroupInternal(ri int, groupIndex, quantity uint) error {
|
||||
return e.NewEntityNotExistsError("group #%d", groupIndex)
|
||||
}
|
||||
|
||||
if g.ShipGroups[sgi].State != "In_Orbit" || g.ShipGroups[sgi].Origin != nil || g.ShipGroups[sgi].Range != nil {
|
||||
if g.ShipGroups[sgi].State() != StateInOrbit {
|
||||
return e.NewShipsBusyError()
|
||||
}
|
||||
|
||||
@@ -599,11 +674,12 @@ func (g *Game) createShips(ri int, shipTypeName string, planetNumber int, quanti
|
||||
TypeID: g.Race[ri].ShipTypes[st].ID,
|
||||
Destination: g.Map.Planet[pl].Number,
|
||||
Number: uint(quantity),
|
||||
State: "In_Orbit",
|
||||
Drive: g.Race[ri].Drive,
|
||||
Weapons: g.Race[ri].Weapons,
|
||||
Shields: g.Race[ri].Shields,
|
||||
Cargo: g.Race[ri].Cargo,
|
||||
Tech: map[Tech]float64{
|
||||
TechDrive: g.Race[ri].TechLevel(TechDrive),
|
||||
TechWeapons: g.Race[ri].TechLevel(TechWeapons),
|
||||
TechShields: g.Race[ri].TechLevel(TechShields),
|
||||
TechCargo: g.Race[ri].TechLevel(TechCargo),
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user