arnaucube
arnaucube/gogame-oldPublic Self-hosted repository
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}