arnaucube
arnaucube/gogame-oldPublic Self-hosted repository
gogame-old/models/planet.go
models/planet.goRaw
  1package models
  2
  3import (
  4	"errors"
  5	"strconv"
  6	"time"
  7
  8	"github.com/arnaucube/gogame/database"
  9	"gopkg.in/mgo.v2/bson"
 10)
 11
 12type Process struct {
 13	// if Title == "", is not active, and can build other buildings/research
 14	Title     string // building name / research name + level
 15	Building  string
 16	Ends      time.Time
 17	CountDown int64
 18}
 19
 20type Resources struct {
 21	Metal     int64
 22	Crystal   int64
 23	Deuterium int64
 24	Energy    int64
 25}
 26
 27type Planet struct {
 28	Db           *database.Db
 29	Id           bson.ObjectId `json:"id" bson:"_id,omitempty"`
 30	LastUpdated  time.Time
 31	Size         int64 // fields/slots
 32	Name         string
 33	OwnerId      bson.ObjectId
 34	Resources    Resources
 35	Buildings    map[string]int64
 36	CurrentBuild Process
 37	Research     Process
 38	/*
 39		Buildings types (in the map, all in lowcase):
 40		   	MetalMine       int64
 41		   	CrystalMine     int64
 42		   	DeuteriumMine   int64
 43		   	EnergyMine      int64
 44		   	FusionReactor   int64
 45		   	RoboticsFactory int64
 46		   	Shipyard        int64
 47		   	RessearchLab    int64
 48	*/
 49}
 50
 51func NewPlanet(db *database.Db, size int64, name string, ownerId bson.ObjectId) (*Planet, error) {
 52	newPlanet := Planet{
 53		Db:      db,
 54		Size:    size,
 55		Name:    name,
 56		OwnerId: ownerId,
 57		Resources: Resources{
 58			Metal:     500,
 59			Crystal:   500,
 60			Deuterium: 500,
 61			Energy:    500,
 62		},
 63	}
 64
 65	// in case that wants to start with resources plants
 66	newPlanet.Buildings = make(map[string]int64)
 67	newPlanet.Buildings["metalmine"] = 1
 68	newPlanet.Buildings["crystalmine"] = 1
 69	newPlanet.Buildings["deuteriummine"] = 1
 70	newPlanet.Buildings["energymine"] = 1
 71
 72	err := db.Planets.Insert(newPlanet)
 73	if err != nil {
 74		return nil, err
 75	}
 76
 77	var planet *Planet
 78	err = db.Planets.Find(bson.M{"ownerid": newPlanet.OwnerId}).One(&planet)
 79	if err != nil {
 80		return nil, err
 81	}
 82
 83	return planet, nil
 84}
 85
 86func (p *Planet) GetFromDb() error {
 87	var planet Planet
 88	err := p.Db.Planets.Find(bson.M{"_id": p.Id}).One(&planet)
 89	if err != nil {
 90		return err
 91	}
 92	planet.Db = p.Db
 93	p = &planet
 94	return nil
 95}
 96
 97func (p *Planet) StoreInDb() error {
 98	p.LastUpdated = time.Now()
 99	err := p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
100	return err
101
102}
103
104// GetResources updates the values of resources and returns the value, also updates the user.Resources
105// Resource types: metal, crystal, deuterium, energy
106func (p *Planet) GetResources() (*Resources, error) {
107	// get current values
108	err := p.GetFromDb()
109	if err != nil {
110		return nil, err
111	}
112	// calculate Delta time = currentTime - p.LastUpdated
113	delta := time.Since(p.LastUpdated).Seconds()
114
115	// get Resource-Plant level in each planet
116	// and calculate growth = ResourcePlant.Level for each planet
117	var metalGrowth, crystalGrowth, deuteriumGrowth, energyGrowth int64
118	metalGrowth = metalGrowth + MetalGrowth(p.Buildings["metalmine"], int64(delta))
119	crystalGrowth = crystalGrowth + MetalGrowth(p.Buildings["crystalmine"], int64(delta))
120	deuteriumGrowth = deuteriumGrowth + MetalGrowth(p.Buildings["deuteriummine"], int64(delta))
121	energyGrowth = energyGrowth + MetalGrowth(p.Buildings["energymine"], int64(delta))
122
123	// calculate newAmount = oldAmount + growth
124	p.Resources.Metal = p.Resources.Metal + metalGrowth
125	p.Resources.Crystal = p.Resources.Crystal + crystalGrowth
126	p.Resources.Deuterium = p.Resources.Deuterium + deuteriumGrowth
127	p.Resources.Energy = p.Resources.Energy + energyGrowth
128
129	// store new amount to user db
130	err = p.StoreInDb()
131	if err != nil {
132		return nil, err
133	}
134
135	// return user
136	return &p.Resources, nil
137}
138
139// SpendResources checks if user has enough resources, then substracts the resources, and updates the amounts in the database
140func (p *Planet) SpendResources(r Resources) error {
141	err := p.GetFromDb()
142	if err != nil {
143		return err
144	}
145	if p.Resources.Metal < r.Metal {
146		return errors.New("not enough metal resources")
147	}
148	if p.Resources.Crystal < r.Crystal {
149		return errors.New("not enough crystal resources")
150	}
151	if p.Resources.Deuterium < r.Deuterium {
152		return errors.New("not enough deuterium resources")
153	}
154	if p.Resources.Energy < r.Energy {
155		return errors.New("not enough energy resources")
156	}
157
158	p.Resources.Metal = p.Resources.Metal - r.Metal
159	p.Resources.Crystal = p.Resources.Crystal - r.Crystal
160	p.Resources.Deuterium = p.Resources.Deuterium - r.Deuterium
161	p.Resources.Energy = p.Resources.Energy - r.Energy
162
163	err = p.StoreInDb()
164	if err != nil {
165		return err
166	}
167	return nil
168}
169func (p *Planet) GetBuildingCost(building string) (Resources, error) {
170	switch building {
171	case "metalmine":
172		return MetalMineCost(p.Buildings["metalmine"] + 1), nil
173	case "crystalmine":
174		return CrystalMineCost(p.Buildings["crystalmine"] + 1), nil
175	case "deuteriummine":
176		return DeuteriumMineCost(p.Buildings["deuteriummine"] + 1), nil
177	case "energymine":
178		return EnergyMineCost(p.Buildings["energymine"] + 1), nil
179	case "fusionreactor":
180		return FussionReactorCost(p.Buildings["fusionreactor"] + 1), nil
181	case "roboticsfactory":
182		return RoboticsFactoryCost(p.Buildings["roboticsfactory"] + 1), nil
183	case "shipyard":
184		return ShipyardCost(p.Buildings["shipyard"] + 1), nil
185	case "metalstorage":
186		return MetalStorageCost(p.Buildings["metalstorage"] + 1), nil
187	case "crystalstorage":
188		return CrystalStorageCost(p.Buildings["crystalstorage"] + 1), nil
189	case "deuteriumstorage":
190		return DeuteriumStorageCost(p.Buildings["deuteriumstorage"] + 1), nil
191	case "ressearchlab":
192		return RessearchLabCost(p.Buildings["ressearchlab"] + 1), nil
193	case "alliancedepot":
194		return AllianceDepotCost(p.Buildings["alliancedepot"] + 1), nil
195	case "missilesilo":
196		return MissileSiloCost(p.Buildings["missilesilo"] + 1), nil
197	case "spacedock":
198		return SpaceDockCost(p.Buildings["spacedock"] + 1), nil
199	default:
200		return Resources{}, errors.New("building not found")
201	}
202
203}
204
205// CheckCurrentBuild checks if the planet has a ongoing building in process, and if has finished
206// in case that has finished, updates it in db
207func (p *Planet) CheckCurrentBuild() (bool, error) {
208	if p.CurrentBuild.Title != "" {
209		// the planet is building something, check if has ended
210		if p.CurrentBuild.Ends.Unix() < time.Now().Unix() {
211			// upgrade level of building in planet
212			p.Buildings[p.CurrentBuild.Building] += 1
213
214			// build end
215			p.CurrentBuild.Title = ""
216			p.CurrentBuild.Building = ""
217
218			// store in db
219			err := p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
220			if err != nil {
221				return true, err
222			}
223			return false, nil
224		}
225		p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
226
227		return true, nil
228	}
229	return false, nil
230
231}
232func (p *Planet) UpgradeBuilding(building string) error {
233	busy, err := p.CheckCurrentBuild()
234	if err != nil {
235		return err
236	}
237	if busy {
238		return errors.New("busy")
239	}
240
241	// get current building level, and get the needed resources for next level
242	resourcesNeeded, err := p.GetBuildingCost(building)
243	if err != nil {
244		return err
245	}
246	// get time cost of the build
247	timei64 := ConstructionTime(resourcesNeeded, p.Buildings[building]+1)
248	endsTime := time.Now().Add(time.Second * time.Duration(timei64))
249
250	// if user have enough resources to upgrade the building, upgrade the building
251	err = p.SpendResources(resourcesNeeded)
252	if err != nil {
253		return err
254	}
255	// add current task to planet
256	p.CurrentBuild.Building = building
257	p.CurrentBuild.Title = building + " - Level " + strconv.Itoa(int(p.Buildings[building]))
258	p.CurrentBuild.Ends = endsTime
259	p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
260
261	// store planet in db
262	err = p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
263	return nil
264}