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