You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

309 lines
8.8 KiB

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
}