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.

294 lines
8.0 KiB

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