package arena import ( "context" "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/lego/utils/container/id" "go_dreamfactory/modules" "go_dreamfactory/pb" "go_dreamfactory/sys/configure" cfg "go_dreamfactory/sys/configure/structs" "go_dreamfactory/sys/db" "math" "math/rand" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/x/bsonx" ) // /竞技场 数据组件 type modelArena struct { modules.MCompModel module *Arena } // 组件初始化接口 func (this *modelArena) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) { this.TableName = comm.TableArena this.MCompModel.Init(service, module, comp, opt) this.module = module.(*Arena) //创建uid索引 if _, err = this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{ {Key: "uid", Value: bsonx.Int32(1)}, }, }); err != nil { return } _, err = this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bson.M{"loc": "2dsphere"}, }) return } // 查询用户装备数据 func (this *modelArena) queryPlayerInfo(uId string) (result *pb.DBArenaUser, err error) { result = &pb.DBArenaUser{} if err = this.Get(uId, result); err != nil && err != mgo.MongodbNil { this.module.Errorln(err) return } return } // 查询用户装备数据 func (this *modelArena) queryPlayers(uIds []string) (result []*pb.DBArenaUser, err error) { result = make([]*pb.DBArenaUser, 0) if _, err = this.Gets(uIds, &result); err != nil && err != mgo.MongodbNil { this.module.Errorln(err) return } return } // 查询用户装备数据 func (this *modelArena) queryArenaPlayer(uId string) (result *pb.ArenaPlayer, err error) { temp := &pb.DBArenaUser{} if err = this.Get(uId, temp); err != nil { this.module.Errorln(err) return } result = &pb.ArenaPlayer{ Uid: temp.Uid, Name: temp.Name, // Avatar: temp.Avatar, Lv: temp.Lv, Sex: temp.Sex, Skin: temp.Skin, Dan: temp.Dan, Integral: temp.Integral, Defend: temp.Defend, Isai: false, } return } // 查询用户英雄数据 func (this *modelArena) queryUserHeros(uid string, heroids []string) (results []*pb.DBHero, err error) { var ( model *db.DBModel ) if model, err = this.module.GetDBModelByUid(uid, comm.TableHero); err != nil { this.module.Errorln(err) return } results = make([]*pb.DBHero, 0) if err = model.GetListObjs(uid, heroids, &results); err != nil { this.module.Errorln(err) return } return } // /保存用户竞技场信息 func (this *modelArena) updateArenaUserInfo(info *pb.DBArenaUser) (err error) { var ( dan int32 ) if dan, err = this.computedan(info.Integral); err != nil { return } info.Dan = dan this.Change(info.Uid, map[string]interface{}{ "integral": info.Integral, "dan": dan, "rank": info.Rank, // "ticket": info.Ticket, "buynum": info.Buynum, "lastrtickettime": info.Lastrtickettime, "attack": info.Attack, "defend": info.Defend, "streak": info.Streak, "record": info.Record, "attackwinuum": info.Attackwinuum, "attacktotaluum": info.Attacktotaluum, "defendwinuum": info.Defendwinuum, "defendtotaluum": info.Defendtotaluum, "loc": []float64{float64(dan), float64(rand.Int31n(100)) / 1000.0}, "isdef": info.Isdef, "name": info.Name, "lv": info.Lv, "sex": info.Sex, "skin": info.Skin, }) return } func (this *modelArena) modifyIntegral(uid string, integral int32) (err error) { var ( dan int32 player *pb.ArenaPlayer ) if dan, err = this.computedan(integral); err != nil { return } player = &pb.ArenaPlayer{Uid: uid, Integral: integral} if err = this.module.modelRank.updateArenaRank(player); err != nil { this.module.Errorln(err) return } this.Change(uid, map[string]interface{}{ "integral": integral, "dan": dan, "rank": player.Rank, }) return } func (this *modelArena) computedan(integral int32) (dan int32, err error) { var ( active *cfg.GameArenaActiveRewardData ) if active, err = this.module.configure.getActiveReward(integral); err != nil { this.module.Errorln(err) return } dan = active.LvId return } //获取目标去陪数据 // func (this *modelArena) matchePlayer(integral int32) (results []*pb.DBArenaUser, err error) { // var ( // cursor *mongo.Cursor // ) // project := bson.M{"$project": bson.M{ // "diff": bson.M{ // "$abs": bson.M{"$subtract": bson.A{integral, "$start"}}, // }, // }} // if cursor, err = this.DBModel.DB.Aggregate(comm.TableArena, bson.A{project}); err != nil { // this.module.Errorln(err) // return // } else { // for cursor.Next(context.Background()) { // temp := &pb.DBArenaUser{} // if err = cursor.Decode(temp); err != nil { // this.module.Errorln(err) // return // } // } // } // return // } // 匹配机器人 func (this *modelArena) matcheAI(dan, num int32) (results []*pb.ArenaPlayer, err error) { var ( active *cfg.GameArenaActiveRewardData ais []*cfg.GameArenaRobotData formats []*cfg.GameMonsterFormatData robots []*cfg.GameRobotData rank []int32 targets []int32 ) if active, err = this.module.configure.getActiveRewardById(dan); err != nil { this.module.Errorln(err) return } if ais, err = this.module.configure.getArenaRobot(dan); err != nil { this.module.Errorln(err) return } rank = make([]int32, len(ais)) for i, v := range ais { rank[i] = v.Weight } targets = make([]int32, num) for i := 0; i < int(num); i++ { index := comm.GetRandW(rank) targets[i] = index } results = make([]*pb.ArenaPlayer, num) if robots, err = this.module.ModuleTools.RandRobotConfig(int32(len(targets))); err != nil { return } for i, v := range targets { aiconf := ais[v] if formats, err = this.module.configure.getMonsterFormat(aiconf.MonsterformatId); err != nil { this.module.Errorln(err) return } results[i] = &pb.ArenaPlayer{ Uid: fmt.Sprintf("ai_%s", id.NewXId()), Name: robots[i].Name, Lv: robots[i].Lvshow, Sex: robots[i].Sex, Skin: robots[i].Showid, Dan: dan, Integral: int32(rand.Intn(int(active.ScoreUp)-int(active.ScoreLow))) + active.ScoreLow, Isai: true, Mformatid: aiconf.MonsterformatId, Defend: &pb.DBPlayerBattleFormt{ Leadpos: 0, Formt: make([]*pb.DBHero, len(formats)), }, } for i1, v1 := range formats { if v1 == nil { results[i].Defend.Formt[i1] = nil } else { if v1.CaptainId == 1 { results[i].Defend.Leadpos = int32(i1) } // if monst, err = this.module.configure.getMonster(v1.Monster); err != nil { // this.module.Errorln(err) // } hero := &pb.DBHero{} if hero = this.module.ModuleHero.CreateMonster(fmt.Sprintf("%d", v1.Heroid), v1.Star, v1.Lv); hero == nil { err = fmt.Errorf("CreateMonster 失败") return } hero.Property[comm.Hp] = int32(float32(hero.Property[comm.Hp]) * v1.Hppro) hero.Property[comm.Atk] = int32(float32(hero.Property[comm.Atk]) * v1.Atkpro) hero.Property[comm.Def] = int32(float32(hero.Property[comm.Def]) * v1.Defpro) hero.Suits = make([]*pb.DB_EquipmentSuit, 0) for _, v := range v1.Equip { hero.Suits = append(hero.Suits, &pb.DB_EquipmentSuit{ Suitid: v, Effect: true, }) } results[i].Defend.Formt[i1] = hero } } } return } // 获取目标去陪数据 func (this *modelArena) matchePlayer(uid string, dan, num int32) (results []*pb.ArenaPlayer, err error) { var ( cursor *mongo.Cursor ) results = make([]*pb.ArenaPlayer, 0) port := []float64{float64(dan), float64(rand.Int31n(100)) / 1000.0} if cursor, err = this.DBModel.DB.Find(comm.TableArena, bson.M{ "isdef": true, "uid": bson.M{"$ne": uid}, "dan": dan, "loc": bson.M{ "$near": bson.M{ "$geometry": bson.M{"type": "Point", "coordinates": port}, "$maxDistance": 100000, }, }, }, options.Find().SetSkip(0).SetLimit(int64(num))); err != nil { this.module.Errorln(err) return } else { for cursor.Next(context.Background()) { temp := &pb.DBArenaUser{} if err = cursor.Decode(temp); err != nil { this.module.Errorln(err) return } results = append(results, &pb.ArenaPlayer{ Uid: temp.Uid, Name: temp.Name, // Avatar: temp.Avatar, Lv: temp.Lv, Dan: temp.Dan, Integral: temp.Integral, Defend: temp.Defend, }) } } return } // 随机用户名 func (this *modelArena) randUserName() string { var s = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*") r := rand.New(rand.NewSource(configure.Now().UnixNano() + rand.Int63n(10000))) result := []byte("DWA_") for i, v := range r.Perm(len(s)) { result = append(result, s[v]) if i == 3 { break } } return string(result) } func (this *modelArena) getAI(mformatId int32) (ai *pb.ArenaPlayer, err error) { var ( formats []*cfg.GameMonsterFormatData // monst *cfg.GameMonsterData ) if formats, err = this.module.configure.getMonsterFormat(mformatId); err != nil { this.module.Errorln(err) return } ai = &pb.ArenaPlayer{ Name: this.randUserName(), Isai: true, Mformatid: mformatId, Defend: &pb.DBPlayerBattleFormt{ Leadpos: 0, Formt: make([]*pb.DBHero, len(formats)), }, } for i1, v1 := range formats { if v1 == nil { ai.Defend.Formt[i1] = nil } else { // if monst, err = this.module.configure.getMonster(v1.Monster); err != nil { // this.module.Errorln(err) // } hero := &pb.DBHero{} if hero = this.module.ModuleHero.CreateMonster(fmt.Sprintf("%d", v1.Heroid), v1.Star, v1.Lv); hero == nil { err = fmt.Errorf("CreateMonster 失败") return } hero.Property[comm.Hp] = int32(float32(hero.Property[comm.Hp]) * v1.Hppro) hero.Property[comm.Atk] = int32(float32(hero.Property[comm.Atk]) * v1.Atkpro) hero.Property[comm.Def] = int32(float32(hero.Property[comm.Def]) * v1.Defpro) hero.Suits = make([]*pb.DB_EquipmentSuit, 0) for _, v := range v1.Equip { hero.Suits = append(hero.Suits, &pb.DB_EquipmentSuit{ Suitid: v, Effect: true, }) } ai.Defend.Formt[i1] = hero } } return } // 积分计算 func (this *modelArena) integralCompute(red, bule *pb.ArenaPlayer, iswin bool) { var ( redactive *cfg.GameArenaActiveRewardData buleactive *cfg.GameArenaActiveRewardData err error ) if redactive, err = this.module.configure.getActiveRewardById(red.Dan); err != nil { this.module.Errorln(err) return } if buleactive, err = this.module.configure.getActiveRewardById(bule.Dan); err != nil { this.module.Errorln(err) return } if iswin { red.Changeintegral = int32(redactive.KValue * float32(1-1/float32(1+10^(bule.Integral-red.Integral)/400))) red.Integral = red.Integral + red.Changeintegral bule.Changeintegral = int32(buleactive.KValue * float32(0-1/float32(1+10^(red.Integral-bule.Integral)/400))) bule.Integral = bule.Integral + bule.Changeintegral } else { red.Changeintegral = int32(redactive.KValue * float32(0-1/float32(1+10^(bule.Integral-red.Integral)/400))) red.Integral = red.Integral + red.Changeintegral bule.Changeintegral = int32(redactive.KValue * float32(1-1/float32(1+10^(red.Integral-bule.Integral)/400))) bule.Integral = bule.Integral + bule.Changeintegral } } func (this *modelArena) recoverTicket(session comm.IUserSession, info *pb.DBArenaUser) { var ( duration time.Duration ticketitem *cfg.Gameatn ticket int32 ticketNum int32 ) if ticketitem = this.module.ModuleTools.GetGlobalConf().ArenaTicketCos; ticketitem == nil { this.module.Error("竞技场配置未找到!", log.Field{Key: "key", Value: "ArenaTicketCos"}) return } global := this.module.ModuleTools.GetGlobalConf() maxTick := global.ArenaTicketMax // 竞技场最大上限 maxTick += this.module.privilege.GetCountByPrivilegeId(session.GetUserId(), comm.PrivilegeType10) // 特权 ticket = int32(this.module.ModuleItems.QueryItemAmount(info.Uid, ticketitem.T)) if ticket < maxTick && info.Lastrtickettime > 0 { duration = configure.Now().Sub(time.Unix(info.Lastrtickettime, 0)) ticketNum = int32(math.Floor(duration.Minutes() / float64(global.ArenaTicketRecoveryTime))) if ticketNum > 0 { if ticketNum+ticket > global.ArenaTicketMax { ticketNum = global.ArenaTicketMax - ticket } this.module.DispenseRes(session, []*cfg.Gameatn{{A: ticketitem.A, T: ticketitem.T, N: ticketNum}}, true) info.Lastrtickettime = time.Unix(info.Lastrtickettime, 0).Add(time.Duration(ticketNum) * time.Minute).Unix() } } } func (this *modelArena) reddot(session comm.IUserSession) bool { var ( info *pb.DBArenaUser ticketitem *cfg.Gameatn err error ) if info, err = this.queryPlayerInfo(session.GetUserId()); err != nil && err != mgo.MongodbNil { return false } if err == mgo.MongodbNil { global := this.module.ModuleTools.GetGlobalConf() if global.ArenaTicketMax >= global.ArenaTicketCos.N { return true } return false } if ticketitem = this.module.ModuleTools.GetGlobalConf().ArenaTicketCos; ticketitem == nil { this.module.Error("竞技场配置未找到!", log.Field{Key: "key", Value: "ArenaTicketCos"}) return false } ticket := int32(this.module.ModuleItems.QueryItemAmount(info.Uid, ticketitem.T)) if ticket > this.module.ModuleTools.GetGlobalConf().ArenaTicketCos.N { return true } return false }