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