arnaucube
arnaucube/gogame-oldPublic Self-hosted repository
gogame-old/services/gamesrv/gamesrv.go
services/gamesrv/gamesrv.goRaw
  1package gamesrv
  2
  3import (
  4	"errors"
  5	"fmt"
  6	"strconv"
  7	"time"
  8
  9	"github.com/arnaucube/gogame/constants"
 10	"github.com/arnaucube/gogame/database"
 11	"github.com/arnaucube/gogame/models"
 12	"github.com/arnaucube/gogame/utils"
 13	"gopkg.in/mgo.v2/bson"
 14)
 15
 16type Service struct {
 17	db *database.Db
 18}
 19
 20func New(db *database.Db) *Service {
 21	return &Service{
 22		db,
 23	}
 24}
 25
 26// CreatePlanet is used when a user conquers a planet
 27func (srv Service) CreatePlanet(userId bson.ObjectId) (*models.SolarSystem, *models.Planet, error) {
 28	size := int64(250)   // TODO get rand inside a range
 29	name := "planetname" // TODO get random name
 30
 31	newPlanet := models.Planet{
 32		Size:    size,
 33		Name:    name,
 34		OwnerId: userId,
 35	}
 36	// in case that wants to start with resources plants
 37	newPlanet.Buildings = make(map[string]int64)
 38	newPlanet.Buildings["metalmine"] = 1
 39	newPlanet.Buildings["crystalmine"] = 1
 40	newPlanet.Buildings["deuteriummine"] = 1
 41	newPlanet.Buildings["energymine"] = 1
 42
 43	err := srv.db.Planets.Insert(newPlanet)
 44	if err != nil {
 45		return nil, nil, err
 46	}
 47	var planet *models.Planet
 48	err = srv.db.Planets.Find(bson.M{"ownerid": newPlanet.OwnerId}).One(&planet)
 49	if err != nil {
 50		return nil, nil, err
 51	}
 52
 53	// now put the planet in a solar system
 54	// get random solar system
 55	systemPosition := utils.RandInRange(0, constants.GALAXYSIZE)
 56	solarSystem, err := srv.PutPlanetInSolarSystem(systemPosition, planet)
 57	// TODO if error is returned because there is no empty slots for planets in the solar system in systemPosition, get another systemPosition and try again
 58
 59	return solarSystem, planet, err
 60}
 61
 62func (srv Service) PutPlanetInSolarSystem(position int64, planet *models.Planet) (*models.SolarSystem, error) {
 63	var solarSystem models.SolarSystem
 64	err := srv.db.SolarSystems.Find(bson.M{"position": position}).One(&solarSystem)
 65	if err != nil {
 66		// solar system non existing yet
 67		// create a solarsystem with empty planets
 68		var emptyPlanets []string
 69		for i := 0; i < constants.SOLARSYSTEMSIZE; i++ {
 70			emptyPlanets = append(emptyPlanets, "empty")
 71		}
 72		newSolarSystem := models.SolarSystem{
 73			Position: position,
 74			Planets:  emptyPlanets[:15],
 75		}
 76		err = srv.db.SolarSystems.Insert(newSolarSystem)
 77		if err != nil {
 78			return nil, err
 79		}
 80		err := srv.db.SolarSystems.Find(bson.M{"position": position}).One(&solarSystem)
 81
 82		return &solarSystem, err
 83	}
 84	// get free slots in solarSystem
 85	posInSolarSystem := utils.RandInRange(0, constants.SOLARSYSTEMSIZE)
 86	if solarSystem.Planets[posInSolarSystem] != "" {
 87		// not empty slot, take another one TODO
 88		// if there are no empty slots, return error
 89		fmt.Println("not empty slot")
 90	}
 91	// store planet in solar system
 92	solarSystem.Planets[posInSolarSystem] = planet.Id.String()
 93	err = srv.db.SolarSystems.Update(bson.M{"position": position}, solarSystem)
 94
 95	return &solarSystem, err
 96}
 97
 98// CheckCurrentBuild checks if the planet has a ongoing building in process, and if has finished
 99// in case that has finished, updates it in db
100func (srv Service) CheckCurrentBuild(planet *models.Planet) (bool, error) {
101	if planet.CurrentBuild.Title != "" {
102		// the planet is building something, check if has ended
103		if planet.CurrentBuild.Ends.Unix() < time.Now().Unix() {
104			// upgrade level of building in planet
105			planet.Buildings[planet.CurrentBuild.Building] += 1
106
107			// build end
108			planet.CurrentBuild.Title = ""
109			planet.CurrentBuild.Building = ""
110
111			// store in db
112			err := srv.db.Planets.Update(bson.M{"_id": planet.Id}, planet)
113			if err != nil {
114				return true, err
115			}
116			return false, nil
117		}
118		return true, nil
119	}
120	return false, nil
121
122}
123
124func (srv Service) GetBuildings(user *models.User, planetid bson.ObjectId) (*models.Planet, error) {
125	var planet models.Planet
126	err := srv.db.Planets.Find(bson.M{"_id": planetid, "ownerid": user.Id}).One(&planet)
127	if err != nil {
128		return nil, err
129	}
130	_, err = srv.CheckCurrentBuild(&planet)
131	return &planet, err
132}
133
134func (srv Service) UpgradeBuilding(user *models.User, planetid bson.ObjectId, building string) (*models.Planet, error) {
135	// get planet
136	var planet models.Planet
137	err := srv.db.Planets.Find(bson.M{"_id": planetid}).One(&planet)
138	if err != nil {
139		return nil, err
140	}
141	busy, err := srv.CheckCurrentBuild(&planet)
142	if err != nil {
143		return nil, err
144	}
145	if busy {
146		return nil, errors.New("busy")
147	}
148
149	// get current building level, and get the needed resources for next level
150	resourcesNeeded, err := user.GetBuildingCost(planet, building)
151	if err != nil {
152		return nil, err
153	}
154	// get time cost of the build
155	timei64 := models.ConstructionTime(resourcesNeeded, planet.Buildings[building]+1)
156	endsTime := time.Now().Add(time.Second * time.Duration(timei64))
157
158	// if user have enough resources to upgrade the building, upgrade the building
159	err = user.SpendResources(resourcesNeeded)
160	if err != nil {
161		return nil, err
162	}
163	// add current task to planet
164	planet.CurrentBuild.Building = building
165	planet.CurrentBuild.Title = building + " - Level " + strconv.Itoa(int(planet.Buildings[building]))
166	planet.CurrentBuild.Ends = endsTime
167
168	// store planet in db
169	err = srv.db.Planets.Update(bson.M{"_id": planet.Id}, planet)
170	return &planet, nil
171}