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}