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