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 LastUpdated: time.Now(),
55 Size: size,
56 Name: name,
57 OwnerId: ownerId,
58 Resources: Resources{
59 Metal: 500,
60 Crystal: 500,
61 Deuterium: 500,
62 Energy: 500,
63 },
64 }
65
66 // in case that wants to start with resources plants
67 newPlanet.Buildings = make(map[string]int64)
68 newPlanet.Buildings["metalmine"] = 1
69 newPlanet.Buildings["crystalmine"] = 1
70 newPlanet.Buildings["deuteriummine"] = 1
71 // newPlanet.Buildings["energymine"] = 1
72
73 err := db.Planets.Insert(newPlanet)
74 if err != nil {
75 return nil, err
76 }
77
78 var planet *Planet
79 err = db.Planets.Find(bson.M{"ownerid": newPlanet.OwnerId}).One(&planet)
80 if err != nil {
81 return nil, err
82 }
83
84 return planet, nil
85}
86
87func (p *Planet) GetFromDb() error {
88 var planet Planet
89 err := p.Db.Planets.Find(bson.M{"_id": p.Id}).One(&planet)
90 if err != nil {
91 return err
92 }
93 planet.Db = p.Db
94 p = &planet
95 return nil
96}
97
98func (p *Planet) StoreInDb() error {
99 p.LastUpdated = time.Now()
100 err := p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
101 return err
102
103}
104
105// GetResources updates the values of resources and returns the value, also updates the user.Resources
106// Resource types: metal, crystal, deuterium, energy
107func (p *Planet) GetResources() (*Resources, error) {
108 // get current values
109 err := p.GetFromDb()
110 if err != nil {
111 return nil, err
112 }
113 // calculate Delta time = currentTime - p.LastUpdated
114 delta := time.Since(p.LastUpdated).Seconds()
115
116 // get Resource-Plant level in each planet
117 // and calculate growth = ResourcePlant.Level for each planet
118 var metalGrowth, crystalGrowth, deuteriumGrowth int64
119 metalGrowth = metalGrowth + MetalGrowth(p.Buildings["metalmine"], int64(delta))
120 crystalGrowth = crystalGrowth + CrystalGrowth(p.Buildings["crystalmine"], int64(delta))
121 deuteriumGrowth = deuteriumGrowth + DeuteriumGrowth(p.Buildings["deuteriummine"], int64(delta))
122
123 // get energy generated and used
124 energyGenerated := int64(500)
125 energyGenerated = energyGenerated + SolarGrowth(p.Buildings["energymine"])
126 var energyUsed int64
127 energyUsed = energyUsed + MetalMineEnergyConsumption(p.Buildings["metalmine"])
128 energyUsed = energyUsed + CrystalMineEnergyConsumption(p.Buildings["crystalmine"])
129 energyUsed = energyUsed + DeuteriumMineEnergyConsumption(p.Buildings["deuteriummine"])
130
131 // calculate newAmount = oldAmount + growth
132 p.Resources.Metal = p.Resources.Metal + metalGrowth
133 p.Resources.Crystal = p.Resources.Crystal + crystalGrowth
134 p.Resources.Deuterium = p.Resources.Deuterium + deuteriumGrowth
135 p.Resources.Energy = energyGenerated - energyUsed
136
137 // store new amount to user db
138 err = p.StoreInDb()
139 if err != nil {
140 return nil, err
141 }
142
143 return &p.Resources, nil
144}
145
146// SpendResources checks if user has enough resources, then substracts the resources, and updates the amounts in the database
147func (p *Planet) SpendResources(r Resources) error {
148 err := p.GetFromDb()
149 if err != nil {
150 return err
151 }
152 if p.Resources.Metal < r.Metal {
153 return errors.New("not enough metal resources")
154 }
155 if p.Resources.Crystal < r.Crystal {
156 return errors.New("not enough crystal resources")
157 }
158 if p.Resources.Deuterium < r.Deuterium {
159 return errors.New("not enough deuterium resources")
160 }
161 // if p.Resources.Energy < r.Energy {
162 // return errors.New("not enough energy resources")
163 // }
164
165 p.Resources.Metal = p.Resources.Metal - r.Metal
166 p.Resources.Crystal = p.Resources.Crystal - r.Crystal
167 p.Resources.Deuterium = p.Resources.Deuterium - r.Deuterium
168 p.Resources.Energy = p.Resources.Energy - r.Energy
169
170 err = p.StoreInDb()
171 if err != nil {
172 return err
173 }
174 return nil
175}
176func (p *Planet) GetBuildingCost(building string) (Resources, error) {
177 switch building {
178 case "metalmine":
179 return MetalMineCost(p.Buildings["metalmine"] + 1), nil
180 case "crystalmine":
181 return CrystalMineCost(p.Buildings["crystalmine"] + 1), nil
182 case "deuteriummine":
183 return DeuteriumMineCost(p.Buildings["deuteriummine"] + 1), nil
184 case "energymine":
185 return EnergyMineCost(p.Buildings["energymine"] + 1), nil
186 case "fusionreactor":
187 return FussionReactorCost(p.Buildings["fusionreactor"] + 1), nil
188 case "roboticsfactory":
189 return RoboticsFactoryCost(p.Buildings["roboticsfactory"] + 1), nil
190 case "shipyard":
191 return ShipyardCost(p.Buildings["shipyard"] + 1), nil
192 case "metalstorage":
193 return MetalStorageCost(p.Buildings["metalstorage"] + 1), nil
194 case "crystalstorage":
195 return CrystalStorageCost(p.Buildings["crystalstorage"] + 1), nil
196 case "deuteriumstorage":
197 return DeuteriumStorageCost(p.Buildings["deuteriumstorage"] + 1), nil
198 case "ressearchlab":
199 return RessearchLabCost(p.Buildings["ressearchlab"] + 1), nil
200 case "alliancedepot":
201 return AllianceDepotCost(p.Buildings["alliancedepot"] + 1), nil
202 case "missilesilo":
203 return MissileSiloCost(p.Buildings["missilesilo"] + 1), nil
204 case "spacedock":
205 return SpaceDockCost(p.Buildings["spacedock"] + 1), nil
206 default:
207 return Resources{}, errors.New("building not found")
208 }
209
210}
211
212// CheckCurrentBuild checks if the planet has a ongoing building in process, and if has finished
213// in case that has finished, updates it in db
214func (p *Planet) CheckCurrentBuild() (bool, error) {
215 if p.CurrentBuild.Title != "" {
216 // the planet is building something, check if has ended
217 if p.CurrentBuild.Ends.Unix() < time.Now().Unix() {
218 // add points for resources spend
219 resourcesNeeded, err := p.GetBuildingCost(p.CurrentBuild.Building)
220 if err != nil {
221 return true, err
222 }
223
224 // add points for resources used (each 1000 units, 1 point
225 points := ResourcesToPoints(resourcesNeeded)
226 // 1000 point is the 1 point for the building
227 points += 1000
228 err = AddPoints(p.Db, p.OwnerId, points)
229 if err != nil {
230 return true, err
231 }
232
233 // upgrade level of building in planet
234 p.Buildings[p.CurrentBuild.Building] += 1
235
236 // substrate the energy used by the building
237 var usedEnergy int64
238 if p.CurrentBuild.Building == "metalmine" {
239 usedEnergy = MetalMineEnergyConsumption(p.Buildings["metalmine"])
240 } else if p.CurrentBuild.Building == "crystalmine" {
241 usedEnergy = CrystalMineEnergyConsumption(p.Buildings["crystalmine"])
242 } else if p.CurrentBuild.Building == "deuteriummine" {
243 usedEnergy = DeuteriumMineEnergyConsumption(p.Buildings["deuteriummine"])
244 }
245 p.Resources.Energy = p.Resources.Energy - usedEnergy
246
247 // build end
248 p.CurrentBuild.Title = ""
249 p.CurrentBuild.Building = ""
250
251 // store in db
252 err = p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
253 if err != nil {
254 return true, err
255 }
256 return false, nil
257 }
258 p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
259
260 return true, nil
261 }
262 return false, nil
263
264}
265
266func (p *Planet) UpgradeBuilding(building string) error {
267 busy, err := p.CheckCurrentBuild()
268 if err != nil {
269 return err
270 }
271 if busy {
272 return errors.New("busy")
273 }
274
275 // get current building level, and get the needed resources for next level
276 resourcesNeeded, err := p.GetBuildingCost(building)
277 if err != nil {
278 return err
279 }
280 resourcesNeeded.Energy = 0
281 // get time cost of the build
282 timei64 := ConstructionTime(resourcesNeeded, p.Buildings["roboticsfactory"])
283 endsTime := time.Now().Add(time.Second * time.Duration(timei64))
284
285 // if user have enough resources to upgrade the building, upgrade the building
286 err = p.SpendResources(resourcesNeeded)
287 if err != nil {
288 return err
289 }
290
291 // add current task to planet
292 p.CurrentBuild.Building = building
293 p.CurrentBuild.Title = building + " - Level " + strconv.Itoa(int(p.Buildings[building])+1)
294 p.CurrentBuild.Ends = endsTime
295 p.CurrentBuild.CountDown = p.CurrentBuild.Ends.Unix() - time.Now().Unix()
296
297 // store planet in db
298 err = p.Db.Planets.Update(bson.M{"_id": p.Id}, p)
299 return nil
300}
301
302func ResourcesToPoints(r Resources) int64 {
303 p := int64(0)
304 p = p + r.Metal
305 p = p + r.Crystal
306 p = p + r.Deuterium
307 p = p + r.Energy
308 return p
309}