package gamesrv import ( "errors" "fmt" "strconv" "time" "github.com/arnaucube/gogame/constants" "github.com/arnaucube/gogame/database" "github.com/arnaucube/gogame/models" "github.com/arnaucube/gogame/utils" "gopkg.in/mgo.v2/bson" ) type Service struct { db *database.Db } func New(db *database.Db) *Service { return &Service{ db, } } // CreatePlanet is used when a user conquers a planet func (srv Service) CreatePlanet(userId bson.ObjectId) (*models.SolarSystem, *models.Planet, error) { size := int64(250) // TODO get rand inside a range name := "planetname" // TODO get random name newPlanet := models.Planet{ Size: size, Name: name, OwnerId: userId, } // in case that wants to start with resources plants newPlanet.Buildings = make(map[string]int64) newPlanet.Buildings["metalmine"] = 1 newPlanet.Buildings["crystalmine"] = 1 newPlanet.Buildings["deuteriummine"] = 1 newPlanet.Buildings["energymine"] = 1 err := srv.db.Planets.Insert(newPlanet) if err != nil { return nil, nil, err } var planet *models.Planet err = srv.db.Planets.Find(bson.M{"ownerid": newPlanet.OwnerId}).One(&planet) if err != nil { return nil, nil, err } // now put the planet in a solar system // get random solar system systemPosition := utils.RandInRange(0, constants.GALAXYSIZE) solarSystem, err := srv.PutPlanetInSolarSystem(systemPosition, planet) // 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 return solarSystem, planet, err } func (srv Service) PutPlanetInSolarSystem(position int64, planet *models.Planet) (*models.SolarSystem, error) { var solarSystem models.SolarSystem err := srv.db.SolarSystems.Find(bson.M{"position": position}).One(&solarSystem) if err != nil { // solar system non existing yet // create a solarsystem with empty planets var emptyPlanets []string for i := 0; i < constants.SOLARSYSTEMSIZE; i++ { emptyPlanets = append(emptyPlanets, "empty") } newSolarSystem := models.SolarSystem{ Position: position, Planets: emptyPlanets[:15], } err = srv.db.SolarSystems.Insert(newSolarSystem) if err != nil { return nil, err } err := srv.db.SolarSystems.Find(bson.M{"position": position}).One(&solarSystem) return &solarSystem, err } // get free slots in solarSystem posInSolarSystem := utils.RandInRange(0, constants.SOLARSYSTEMSIZE) if solarSystem.Planets[posInSolarSystem] != "" { // not empty slot, take another one TODO // if there are no empty slots, return error fmt.Println("not empty slot") } // store planet in solar system solarSystem.Planets[posInSolarSystem] = planet.Id.String() err = srv.db.SolarSystems.Update(bson.M{"position": position}, solarSystem) return &solarSystem, err } // CheckCurrentBuild checks if the planet has a ongoing building in process, and if has finished // in case that has finished, updates it in db func (srv Service) CheckCurrentBuild(planet *models.Planet) (bool, error) { if planet.CurrentBuild.Title != "" { // the planet is building something, check if has ended if planet.CurrentBuild.Ends.Unix() < time.Now().Unix() { // upgrade level of building in planet planet.Buildings[planet.CurrentBuild.Building] += 1 // build end planet.CurrentBuild.Title = "" planet.CurrentBuild.Building = "" // store in db err := srv.db.Planets.Update(bson.M{"_id": planet.Id}, planet) if err != nil { return true, err } return false, nil } return true, nil } return false, nil } func (srv Service) GetBuildings(user *models.User, planetid bson.ObjectId) (*models.Planet, error) { var planet models.Planet err := srv.db.Planets.Find(bson.M{"_id": planetid, "ownerid": user.Id}).One(&planet) if err != nil { return nil, err } _, err = srv.CheckCurrentBuild(&planet) return &planet, err } func (srv Service) UpgradeBuilding(user *models.User, planetid bson.ObjectId, building string) (*models.Planet, error) { // get planet var planet models.Planet err := srv.db.Planets.Find(bson.M{"_id": planetid}).One(&planet) if err != nil { return nil, err } busy, err := srv.CheckCurrentBuild(&planet) if err != nil { return nil, err } if busy { return nil, errors.New("busy") } // get current building level, and get the needed resources for next level resourcesNeeded, err := user.GetBuildingCost(planet, building) if err != nil { return nil, err } // get time cost of the build timei64 := models.ConstructionTime(resourcesNeeded, planet.Buildings[building]+1) endsTime := time.Now().Add(time.Second * time.Duration(timei64)) // if user have enough resources to upgrade the building, upgrade the building err = user.SpendResources(resourcesNeeded) if err != nil { return nil, err } // add current task to planet planet.CurrentBuild.Building = building planet.CurrentBuild.Title = building + " - Level " + strconv.Itoa(int(planet.Buildings[building])) planet.CurrentBuild.Ends = endsTime // store planet in db err = srv.db.Planets.Update(bson.M{"_id": planet.Id}, planet) return &planet, nil }