You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
7.2 KiB

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