package models
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/arnaucube/gogame/database"
|
|
"gopkg.in/mgo.v2/bson"
|
|
)
|
|
|
|
type Process struct {
|
|
// if Title == "", is not active, and can build other buildings/research
|
|
Title string // building name / research name + level
|
|
Building string
|
|
Ends time.Time
|
|
CountDown int64
|
|
}
|
|
|
|
type Resources struct {
|
|
Metal int64
|
|
Crystal int64
|
|
Deuterium int64
|
|
Energy int64
|
|
}
|
|
|
|
type Planet struct {
|
|
Db *database.Db
|
|
Id bson.ObjectId `json:"id" bson:"_id,omitempty"`
|
|
LastUpdated time.Time
|
|
Size int64 // fields/slots
|
|
Name string
|
|
OwnerId bson.ObjectId
|
|
Resources Resources
|
|
Buildings map[string]int64
|
|
CurrentBuild Process
|
|
Research Process
|
|
/*
|
|
Buildings types (in the map, all in lowcase):
|
|
MetalMine int64
|
|
CrystalMine int64
|
|
DeuteriumMine int64
|
|
EnergyMine int64
|
|
FusionReactor int64
|
|
RoboticsFactory int64
|
|
Shipyard int64
|
|
RessearchLab int64
|
|
*/
|
|
}
|
|
|
|
func NewPlanet(db *database.Db, size int64, name string, ownerId bson.ObjectId) (*Planet, error) {
|
|
newPlanet := Planet{
|
|
Db: db,
|
|
LastUpdated: time.Now(),
|
|
Size: size,
|
|
Name: name,
|
|
OwnerId: ownerId,
|
|
Resources: Resources{
|
|
Metal: 500,
|
|
Crystal: 500,
|
|
Deuterium: 500,
|
|
Energy: 500,
|
|
},
|
|
}
|
|
|
|
// in case that wants to start with resources plants
|
|
newPlanet.Buildings = make(map[string]int64)
|
|
newPlanet.Buildings["metalmine"] = 1
|
|
newPlanet.Buildings["crystalmine"] = 1
|
|
newPlanet.Buildings["deuteriummine"] = 1
|
|
// newPlanet.Buildings["energymine"] = 1
|
|
|
|
err := db.Planets.Insert(newPlanet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var planet *Planet
|
|
err = db.Planets.Find(bson.M{"ownerid": newPlanet.OwnerId}).One(&planet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return planet, nil
|
|
}
|
|
|
|
func (p *Planet) GetFromDb() error {
|
|
var planet Planet
|
|
err := p.Db.Planets.Find(bson.M{"_id": p.Id}).One(&planet)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
planet.Db = p.Db
|
|
p = &planet
|
|
return nil
|
|
}
|
|
|
|
func (p *Planet) StoreInDb() error {
|
|
p.LastUpdated = time.Now()
|
|
err := p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
|
|
return err
|
|
|
|
}
|
|
|
|
// GetResources updates the values of resources and returns the value, also updates the user.Resources
|
|
// Resource types: metal, crystal, deuterium, energy
|
|
func (p *Planet) GetResources() (*Resources, error) {
|
|
// get current values
|
|
err := p.GetFromDb()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// calculate Delta time = currentTime - p.LastUpdated
|
|
delta := time.Since(p.LastUpdated).Seconds()
|
|
|
|
// get Resource-Plant level in each planet
|
|
// and calculate growth = ResourcePlant.Level for each planet
|
|
var metalGrowth, crystalGrowth, deuteriumGrowth int64
|
|
metalGrowth = metalGrowth + MetalGrowth(p.Buildings["metalmine"], int64(delta))
|
|
crystalGrowth = crystalGrowth + CrystalGrowth(p.Buildings["crystalmine"], int64(delta))
|
|
deuteriumGrowth = deuteriumGrowth + DeuteriumGrowth(p.Buildings["deuteriummine"], int64(delta))
|
|
|
|
// get energy generated and used
|
|
energyGenerated := int64(500)
|
|
energyGenerated = energyGenerated + SolarGrowth(p.Buildings["energymine"])
|
|
var energyUsed int64
|
|
energyUsed = energyUsed + MetalMineEnergyConsumption(p.Buildings["metalmine"])
|
|
energyUsed = energyUsed + CrystalMineEnergyConsumption(p.Buildings["crystalmine"])
|
|
energyUsed = energyUsed + DeuteriumMineEnergyConsumption(p.Buildings["deuteriummine"])
|
|
|
|
// calculate newAmount = oldAmount + growth
|
|
p.Resources.Metal = p.Resources.Metal + metalGrowth
|
|
p.Resources.Crystal = p.Resources.Crystal + crystalGrowth
|
|
p.Resources.Deuterium = p.Resources.Deuterium + deuteriumGrowth
|
|
p.Resources.Energy = energyGenerated - energyUsed
|
|
|
|
// store new amount to user db
|
|
err = p.StoreInDb()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &p.Resources, nil
|
|
}
|
|
|
|
// SpendResources checks if user has enough resources, then substracts the resources, and updates the amounts in the database
|
|
func (p *Planet) SpendResources(r Resources) error {
|
|
err := p.GetFromDb()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if p.Resources.Metal < r.Metal {
|
|
return errors.New("not enough metal resources")
|
|
}
|
|
if p.Resources.Crystal < r.Crystal {
|
|
return errors.New("not enough crystal resources")
|
|
}
|
|
if p.Resources.Deuterium < r.Deuterium {
|
|
return errors.New("not enough deuterium resources")
|
|
}
|
|
// if p.Resources.Energy < r.Energy {
|
|
// return errors.New("not enough energy resources")
|
|
// }
|
|
|
|
p.Resources.Metal = p.Resources.Metal - r.Metal
|
|
p.Resources.Crystal = p.Resources.Crystal - r.Crystal
|
|
p.Resources.Deuterium = p.Resources.Deuterium - r.Deuterium
|
|
p.Resources.Energy = p.Resources.Energy - r.Energy
|
|
|
|
err = p.StoreInDb()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
func (p *Planet) GetBuildingCost(building string) (Resources, error) {
|
|
switch building {
|
|
case "metalmine":
|
|
return MetalMineCost(p.Buildings["metalmine"] + 1), nil
|
|
case "crystalmine":
|
|
return CrystalMineCost(p.Buildings["crystalmine"] + 1), nil
|
|
case "deuteriummine":
|
|
return DeuteriumMineCost(p.Buildings["deuteriummine"] + 1), nil
|
|
case "energymine":
|
|
return EnergyMineCost(p.Buildings["energymine"] + 1), nil
|
|
case "fusionreactor":
|
|
return FussionReactorCost(p.Buildings["fusionreactor"] + 1), nil
|
|
case "roboticsfactory":
|
|
return RoboticsFactoryCost(p.Buildings["roboticsfactory"] + 1), nil
|
|
case "shipyard":
|
|
return ShipyardCost(p.Buildings["shipyard"] + 1), nil
|
|
case "metalstorage":
|
|
return MetalStorageCost(p.Buildings["metalstorage"] + 1), nil
|
|
case "crystalstorage":
|
|
return CrystalStorageCost(p.Buildings["crystalstorage"] + 1), nil
|
|
case "deuteriumstorage":
|
|
return DeuteriumStorageCost(p.Buildings["deuteriumstorage"] + 1), nil
|
|
case "ressearchlab":
|
|
return RessearchLabCost(p.Buildings["ressearchlab"] + 1), nil
|
|
case "alliancedepot":
|
|
return AllianceDepotCost(p.Buildings["alliancedepot"] + 1), nil
|
|
case "missilesilo":
|
|
return MissileSiloCost(p.Buildings["missilesilo"] + 1), nil
|
|
case "spacedock":
|
|
return SpaceDockCost(p.Buildings["spacedock"] + 1), nil
|
|
default:
|
|
return Resources{}, errors.New("building not found")
|
|
}
|
|
|
|
}
|
|
|
|
// CheckCurrentBuild checks if the planet has a ongoing building in process, and if has finished
|
|
// in case that has finished, updates it in db
|
|
func (p *Planet) CheckCurrentBuild() (bool, error) {
|
|
if p.CurrentBuild.Title != "" {
|
|
// the planet is building something, check if has ended
|
|
if p.CurrentBuild.Ends.Unix() < time.Now().Unix() {
|
|
// add points for resources spend
|
|
resourcesNeeded, err := p.GetBuildingCost(p.CurrentBuild.Building)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
// add points for resources used (each 1000 units, 1 point
|
|
points := ResourcesToPoints(resourcesNeeded)
|
|
// 1000 point is the 1 point for the building
|
|
points += 1000
|
|
err = AddPoints(p.Db, p.OwnerId, points)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
// upgrade level of building in planet
|
|
p.Buildings[p.CurrentBuild.Building] += 1
|
|
|
|
// substrate the energy used by the building
|
|
var usedEnergy int64
|
|
if p.CurrentBuild.Building == "metalmine" {
|
|
usedEnergy = MetalMineEnergyConsumption(p.Buildings["metalmine"])
|
|
} else if p.CurrentBuild.Building == "crystalmine" {
|
|
usedEnergy = CrystalMineEnergyConsumption(p.Buildings["crystalmine"])
|
|
} else if p.CurrentBuild.Building == "deuteriummine" {
|
|
usedEnergy = DeuteriumMineEnergyConsumption(p.Buildings["deuteriummine"])
|
|
}
|
|
p.Resources.Energy = p.Resources.Energy - usedEnergy
|
|
|
|
// build end
|
|
p.CurrentBuild.Title = ""
|
|
p.CurrentBuild.Building = ""
|
|
|
|
// store in db
|
|
err = p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
return false, nil
|
|
}
|
|
p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
|
|
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
|
|
}
|
|
|
|
func (p *Planet) UpgradeBuilding(building string) error {
|
|
busy, err := p.CheckCurrentBuild()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if busy {
|
|
return errors.New("busy")
|
|
}
|
|
|
|
// get current building level, and get the needed resources for next level
|
|
resourcesNeeded, err := p.GetBuildingCost(building)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resourcesNeeded.Energy = 0
|
|
// get time cost of the build
|
|
timei64 := ConstructionTime(resourcesNeeded, p.Buildings["roboticsfactory"])
|
|
endsTime := time.Now().Add(time.Second * time.Duration(timei64))
|
|
|
|
// if user have enough resources to upgrade the building, upgrade the building
|
|
err = p.SpendResources(resourcesNeeded)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// add current task to planet
|
|
p.CurrentBuild.Building = building
|
|
p.CurrentBuild.Title = building + " - Level " + strconv.Itoa(int(p.Buildings[building])+1)
|
|
p.CurrentBuild.Ends = endsTime
|
|
p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
|
|
|
|
// store planet in db
|
|
err = p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
|
|
return nil
|
|
}
|
|
|
|
func ResourcesToPoints(r Resources) int64 {
|
|
p := int64(0)
|
|
p = p + r.Metal
|
|
p = p + r.Crystal
|
|
p = p + r.Deuterium
|
|
p = p + r.Energy
|
|
return p
|
|
}
|