package hero import ( "crypto/rand" "errors" "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/modules" "go_dreamfactory/pb" cfg "go_dreamfactory/sys/configure/structs" "go_dreamfactory/sys/db" "go_dreamfactory/utils" "math" "math/big" "reflect" "strconv" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/x/bsonx" ) type ModelHero struct { modules.MCompModel module *Hero } func (this *ModelHero) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.TableName = comm.TableHero err = this.MCompModel.Init(service, module, comp, options) this.module = module.(*Hero) // 通过uid创建索引 this.DB.CreateIndex(core.SqlTable(this.TableName), mongo.IndexModel{ Keys: bsonx.Doc{{Key: "uid", Value: bsonx.Int32(1)}}, }) return } func (p *ModelHero) cloneTags(tags map[int32]int32) map[int32]int32 { cloneTags := make(map[int32]int32) for k, v := range tags { cloneTags[k] = v } return cloneTags } // 计算英雄战力 func (this *ModelHero) calFigthValue(hero *pb.DBHero) (addValue int32, err error) { var ( skillValue int32 // 技能战力 baseValue int32 // 基础战力 heroCfg *cfg.GameHeroData //英雄配置 tmpHero *pb.DBHero preValue int32 skillpos *cfg.GameFightingSkilllvData skilllv *cfg.GameFightingSkilllvData skillStar *cfg.GameFightingSkillStarData ) tmpHero = new(pb.DBHero) *tmpHero = *hero // 克隆一个对象 tmpHero.Property = this.cloneTags(hero.Property) tmpHero.AddProperty = this.cloneTags(hero.AddProperty) tmpHero.JuexProperty = this.cloneTags(hero.JuexProperty) tmpHero.HoroscopeProperty = this.cloneTags(hero.HoroscopeProperty) tmpHero.TalentProperty = this.cloneTags(hero.TalentProperty) preValue = hero.Fightvalue if heroCfg, err = this.module.configure.GetHeroConfig(tmpHero.HeroID); err != nil { return } for k, v := range tmpHero.Property { switch k { case cfg.GamePropertyType_Base_MaxHp_Per: tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Per] = 0 tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base]))) case cfg.GamePropertyType_Base_Atk_Per: tmpHero.Property[cfg.GamePropertyType_Base_Atk_Per] = 0 tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base]))) case cfg.GamePropertyType_Base_Def_Per: tmpHero.Property[cfg.GamePropertyType_Base_Def_Per] = 0 tmpHero.Property[cfg.GamePropertyType_Base_Def_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Def_Base]))) case cfg.GamePropertyType_Base_Speed_Per: tmpHero.Property[cfg.GamePropertyType_Base_Speed_Per] = 0 tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base]))) } } for k, v := range tmpHero.AddProperty { switch k { case cfg.GamePropertyType_Base_MaxHp_Per: tmpHero.AddProperty[cfg.GamePropertyType_Base_MaxHp_Per] = 0 tmpHero.AddProperty[cfg.GamePropertyType_Base_MaxHp_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base]))) case cfg.GamePropertyType_Base_Atk_Per: tmpHero.AddProperty[cfg.GamePropertyType_Base_Atk_Per] = 0 tmpHero.AddProperty[cfg.GamePropertyType_Base_Atk_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base]))) case cfg.GamePropertyType_Base_Def_Per: tmpHero.AddProperty[cfg.GamePropertyType_Base_Def_Per] = 0 tmpHero.AddProperty[cfg.GamePropertyType_Base_Def_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Def_Base]))) case cfg.GamePropertyType_Base_Speed_Per: tmpHero.AddProperty[cfg.GamePropertyType_Base_Speed_Per] = 0 tmpHero.AddProperty[cfg.GamePropertyType_Base_Speed_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base]))) } } for k, v := range tmpHero.JuexProperty { switch k { case cfg.GamePropertyType_Base_MaxHp_Per: tmpHero.JuexProperty[cfg.GamePropertyType_Base_MaxHp_Per] = 0 tmpHero.JuexProperty[cfg.GamePropertyType_Base_MaxHp_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base]))) case cfg.GamePropertyType_Base_Atk_Per: tmpHero.JuexProperty[cfg.GamePropertyType_Base_Atk_Per] = 0 tmpHero.JuexProperty[cfg.GamePropertyType_Base_Atk_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base]))) case cfg.GamePropertyType_Base_Def_Per: tmpHero.JuexProperty[cfg.GamePropertyType_Base_Def_Per] = 0 tmpHero.JuexProperty[cfg.GamePropertyType_Base_Def_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Def_Base]))) case cfg.GamePropertyType_Base_Speed_Per: tmpHero.JuexProperty[cfg.GamePropertyType_Base_Speed_Per] = 0 tmpHero.JuexProperty[cfg.GamePropertyType_Base_Speed_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base]))) } } for k, v := range tmpHero.HoroscopeProperty { switch k { case cfg.GamePropertyType_Base_MaxHp_Per: tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_MaxHp_Per] = 0 tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_MaxHp_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base]))) case cfg.GamePropertyType_Base_Atk_Per: tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Atk_Per] = 0 tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Atk_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base]))) case cfg.GamePropertyType_Base_Def_Per: tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Def_Per] = 0 tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Def_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Def_Base]))) case cfg.GamePropertyType_Base_Speed_Per: tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Speed_Per] = 0 tmpHero.HoroscopeProperty[cfg.GamePropertyType_Base_Speed_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base]))) } } for k, v := range tmpHero.TalentProperty { switch k { case cfg.GamePropertyType_Base_MaxHp_Per: tmpHero.TalentProperty[cfg.GamePropertyType_Base_MaxHp_Per] = 0 tmpHero.TalentProperty[cfg.GamePropertyType_Base_MaxHp_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_MaxHp_Base]))) case cfg.GamePropertyType_Base_Atk_Per: tmpHero.TalentProperty[cfg.GamePropertyType_Base_Atk_Per] = 0 tmpHero.TalentProperty[cfg.GamePropertyType_Base_Atk_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Atk_Base]))) case cfg.GamePropertyType_Base_Def_Per: tmpHero.TalentProperty[cfg.GamePropertyType_Base_Def_Per] = 0 tmpHero.TalentProperty[cfg.GamePropertyType_Base_Def_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Def_Base]))) case cfg.GamePropertyType_Base_Speed_Per: tmpHero.TalentProperty[cfg.GamePropertyType_Base_Speed_Per] = 0 tmpHero.TalentProperty[cfg.GamePropertyType_Base_Speed_Base] += int32(math.Floor((float64(v) / 1000) * float64(tmpHero.Property[cfg.GamePropertyType_Base_Speed_Base]))) } } // 属性汇总 for k, v := range tmpHero.TalentProperty { tmpHero.Property[k] += v } for k, v := range tmpHero.HoroscopeProperty { tmpHero.Property[k] += v } for k, v := range tmpHero.JuexProperty { tmpHero.Property[k] += v } for k, v := range tmpHero.AddProperty { tmpHero.Property[k] += v } // 算基础属性 for k, v := range this.module.configure.GetGameFightingCapacityData() { if _, ok := tmpHero.Property[k]; ok { baseValue += tmpHero.Property[k] * v / 1000 } } for pos, v := range tmpHero.NormalSkill { if skillpos, err = this.module.configure.GetGameFightingSkilllv(int32(pos + 1)); err == nil { if skilllv, err = this.module.configure.GetGameFightingSkilllv(v.SkillLv); err == nil { skillValue += skillpos.Value * skilllv.Value / 1000 } else { return } } else { return } } // 乘以星级系数 if skillStar, err = this.module.configure.GetGameFightingSkillStar(heroCfg.Star); err == nil { skillValue = skillValue * skillStar.Value / 1000 } hero.Fightvalue = skillValue + baseValue addValue = hero.Fightvalue - preValue return } //17 // 初始化英雄 func (this *ModelHero) InitHero(uid string, heroCfgId string) *pb.DBHero { heroCfg, _ := this.module.configure.GetHeroConfig(heroCfgId) if heroCfg == nil { this.module.Errorf("%v hero not found from config %v", heroCfgId) return nil } objId := primitive.NewObjectID().Hex() newHero := &pb.DBHero{ Id: objId, Uid: uid, HeroID: heroCfg.Hid, Star: heroCfg.Star, //初始星级 Lv: 1, //初始等级 Block: false, //未锁定 CardType: heroCfg.Type, //卡片类型 Skins: []int32{}, EquipID: make([]string, 8), //初始装备 AddProperty: make(map[int32]int32), Property: make(map[int32]int32), JuexProperty: make(map[int32]int32), TalentProperty: make(map[int32]int32), HoroscopeProperty: make(map[int32]int32), Fetters: make(map[int32]int32), } this.initHeroSkill(newHero) this.PropertyCompute(newHero) return newHero } // 初始化英雄技能 func (this *ModelHero) initHeroSkill(hero *pb.DBHero) []*pb.SkillData { heroCfg, _ := this.module.configure.GetHeroConfig(hero.HeroID) if heroCfg != nil { if heroCfg.Skill != 0 { hero.CaptainSkill = heroCfg.Skill } skills := []*pb.SkillData{} if heroCfg.Skill1 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill1, SkillLv: 1}) } if heroCfg.Skill2 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill2, SkillLv: 1}) } if heroCfg.Skill3 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill3, SkillLv: 1}) } if heroCfg.Skill4 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill4, SkillLv: 1}) } if heroCfg.Skill5 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill5, SkillLv: 1}) } if heroCfg.Skill6 != 0 { skills = append(skills, &pb.SkillData{SkillID: heroCfg.Skill6, SkillLv: 1}) } hero.NormalSkill = skills } return nil } // 创建一个指定的英雄 func (this *ModelHero) gmCreateSpecialHero(uid string, heroCfgId string) (hero *pb.DBHero, err error) { list := this.getHeroList(uid) for _, v := range list { if v.HeroID == heroCfgId { hero = v return } } hero = this.InitHero(uid, heroCfgId) if hero != nil { if err = this.AddList(uid, hero.Id, hero); err != nil { this.module.Errorf("%v", err) return } } this.module.moduleFetter.AddHeroFetterData(uid, heroCfgId) return } // 拷贝一个指针对象 func (this *ModelHero) copyPoint(m *pb.DBHero) *pb.DBHero { vt := reflect.TypeOf(m).Elem() newoby := reflect.New(vt) newoby.Elem().Set(reflect.ValueOf(m).Elem()) return newoby.Interface().(*pb.DBHero) } // 克隆一个英雄 // 调用此方法前注意有使用map 切片等指针类型数据是 克隆完成后自行初始化这个指针对象 func (this *ModelHero) CloneNewHero(uid string, hero *pb.DBHero) (newHero *pb.DBHero) { newHero = new(pb.DBHero) *newHero = *hero //*this.copyPoint(hero) newHero.Id = primitive.NewObjectID().Hex() this.AddList(newHero.Uid, newHero.Id, newHero) // 星座图属性计算 this.module.moduleHoroscope.ComputeHeroNumeric(uid, hero) return } // 初始化可叠加的英雄 func (this *ModelHero) initHeroOverlying(uid string, heroCfgId string, count int32) (hero *pb.DBHero, err error) { var ( model *db.DBModel ) hero = this.InitHero(uid, heroCfgId) if hero != nil { if this.module.IsCross() { if model, err = this.module.GetDBModelByUid(uid, this.TableName); err != nil { this.module.Errorln(err) } else { if err = model.AddList(uid, hero.Id, hero); err != nil { this.module.Errorf("err:%v", err) } } } else { if err = this.AddList(uid, hero.Id, hero); err != nil { this.module.Errorln(err) } } } return } // 获取一个英雄(参数唯一objID) func (this *ModelHero) getOneHero(uid, heroId string) *pb.DBHero { hero := &pb.DBHero{} err := this.GetListObj(uid, heroId, hero) if err != nil { return nil } return hero } // 获取一个英雄(参数唯一objID) func (this *ModelHero) getHeros(uid string, heroIds []string) (heros []*pb.DBHero, err error) { heros = make([]*pb.DBHero, 0) if err = this.GetListObjs(uid, heroIds, &heros); err != nil { return } return } // 消耗英雄卡 func (this *ModelHero) consumeHeroCard(uid string, hero *pb.DBHero) (err error) { if hero == nil { err = errors.New("hero no exist") return } if err := this.DelListlds(uid, []string{hero.Id}); err != nil { this.module.Errorf("%v", err) } this.module.Debugf("删除卡牌uid:%s,卡牌ID:%s", uid, hero.Id) return } // 获取玩家的英雄列表 func (this *ModelHero) getHeroList(uid string) []*pb.DBHero { heroes := make([]*pb.DBHero, 0) err := this.GetList(uid, &heroes) if err != nil { return nil } return heroes } // 重置觉醒属性 func (this *ModelHero) resetJuexingProperty(hero *pb.DBHero) { hero.JuexProperty = make(map[int32]int32) for i := 1; i <= int(hero.JuexingLv); i++ { awakenData, err := this.module.configure.GetHeroAwakenConfig(hero.HeroID, int32(i)) if err == nil { for _, v := range awakenData.Phasebonus { hero.JuexProperty[v.A] += int32(v.N) } } } } // 设置装备属性 func (this *ModelHero) setEquipProperty(hero *pb.DBHero, equip []*pb.DB_Equipment) { addProperty := make(map[int32]int32) //副属性 equipSkill := make([]*pb.SkillData, 0) for i, v := range equip { if v == nil { continue } hero.EquipID[i] = v.Id addProperty[v.MainEntry.AttrName] += v.MainEntry.Value //主属性 for _, v := range v.AdverbEntry { addProperty[v.AttrName] += v.Value + v.EnchValue //附加属性 } if v.Adverbskill != nil { for _, v := range v.Adverbskill { equipSkill = append(equipSkill, &pb.SkillData{ SkillID: v.SkillId, SkillLv: v.Lv, }) } } } for _, v := range hero.Suits { if v.Effect { if configure, err := this.module.configure.GetEquipsuit(v.Suitid); err != nil { this.module.Errorln(err) } else { for _, v := range configure.SetBonuses { addProperty[v.A] += v.N } } } } this.mergeAddProperty(hero.Uid, hero, addProperty, equipSkill) } // 设置装备 func (this *ModelHero) setEquipment(uid string, hero *pb.DBHero) (newHero *pb.DBHero, err error) { if len(hero.EquipID) == 0 { return } update := make(map[string]interface{}) update["suits"] = hero.Suits update["equipID"] = hero.EquipID if err = this.ChangeList(hero.Uid, hero.Id, update); err != nil { this.module.Errorf("%v", err) return } return } // 合并属性即属性值累加 (data 额外加的属性) // func (this *ModelHero) mergeMainProperty(uid string, hero *pb.DBHero, data map[string]int32) (err error) { // for k, v := range hero.Property { // if v1, ok := data[k]; ok { // v += v1 // } // } // if err = this.ChangeList(uid, hero.Id, map[string]interface{}{ // "property": hero.Property, // }); err != nil { // this.module.Errorf("mergeMainProperty err %v", err) // } // return // } // 合并附加属性 func (this *ModelHero) mergeAddProperty(uid string, hero *pb.DBHero, data map[int32]int32, skills []*pb.SkillData) { hero.AddProperty = data this.calFigthValue(hero) if err := this.ChangeList(uid, hero.Id, map[string]interface{}{ "addProperty": data, "equipSkill": skills, "fightvalue": hero.Fightvalue, }); err != nil { this.module.Errorf("mergeAddProperty err %v", err) } } func (this *ModelHero) StarAtkAddition(star int32) (addValue float32) { for i := 1; i <= int(star); i++ { starCfg := this.module.configure.GetHeroStar(int32(i)) cfg := this.module.configure.GetHeroLv(starCfg.Level) addValue += cfg.Atk * starCfg.StarupAtk / 1000.0 } return addValue } func (this *ModelHero) StarDefAddition(star int32) (addValue float32) { for i := 1; i <= int(star); i++ { starCfg := this.module.configure.GetHeroStar(int32(i)) cfg := this.module.configure.GetHeroLv(starCfg.Level) addValue += cfg.Def * starCfg.StarupDef / 1000.0 } return addValue } func (this *ModelHero) StarHpAddition(star int32) (addValue float32) { for i := 1; i <= int(star); i++ { starCfg := this.module.configure.GetHeroStar(int32(i)) cfg := this.module.configure.GetHeroLv(starCfg.Level) //this.moduleHero.Debugf("cfg.Atk= %f,starCfg.StarupHp = %f,addValue= %f", cfg.Atk, starCfg.StarupHp, addValue) addValue += cfg.Hp * starCfg.StarupHp / 1000.0 } return addValue } // 属性计算 基础属性 // 英雄基础属性 + 英雄等级基础属性 * 英雄成长系数 + 英雄星级对应等级属性 * 英雄品质系数 func (this *ModelHero) PropertyCompute(hero *pb.DBHero) { growCfg := this.module.configure.GetHeroLvgrow(hero.HeroID) heroCfg, _ := this.module.configure.GetHeroConfig(hero.HeroID) lvCfg := this.module.configure.GetHeroLv(hero.Lv) starCfg := this.module.configure.GetHeroStar(hero.Star) starLvfg := this.module.configure.GetHeroLv(starCfg.Level) if growCfg == nil || heroCfg == nil || lvCfg == nil || starCfg == nil || starLvfg == nil { this.module.Debugf("hero propertyCompute Configure Info err:heroid :%s, herolv:=%d,heroStar:%d,", hero.HeroID, hero.Lv, hero.Star) return } var atk = (this.StarAtkAddition(hero.Star) + lvCfg.Atk + float32(growCfg.Atk)) * (growCfg.Atkgrow / 1000.0) var def = (this.StarDefAddition(hero.Star) + lvCfg.Def + float32(growCfg.Def)) * (growCfg.Defgrow / 1000.0) var hp = (this.StarHpAddition(hero.Star) + lvCfg.Hp + float32(growCfg.Hp)) * (growCfg.Hpgrow / 1000.0) speed := growCfg.Speed hero.Property = map[int32]int32{ cfg.GamePropertyType_Base_MaxHp_Base: int32(math.Floor(float64(hp))), cfg.GamePropertyType_Base_Atk_Base: int32(math.Floor(float64(atk))), cfg.GamePropertyType_Base_Def_Base: int32(math.Floor(float64(def))), cfg.GamePropertyType_Base_Speed_Base: int32(math.Floor(float64(speed))), cfg.GamePropertyType_Base_Crit_Base: int32(growCfg.Cri), //暴击 cfg.GamePropertyType_Base_CritDam_Base: int32(growCfg.Cridam), //暴击伤害 cfg.GamePropertyType_Base_EffectHit_Base: int32(growCfg.Effhit), //效果命中 cfg.GamePropertyType_Base_EffectResist_Base: int32(growCfg.Effre), //效果抵抗 cfg.GamePropertyType_LostHold: int32(growCfg.Losthold), //失手率% cfg.GamePropertyType_UnderStand: int32(growCfg.Understand), //会心率% cfg.GamePropertyType_DamRe: int32(growCfg.Damre), //伤害减免% cfg.GamePropertyType_CauseDam: int32(growCfg.Causedam), //伤害提升% cfg.GamePropertyType_TreAdd: int32(growCfg.Treadd), //治疗加成% cfg.GamePropertyType_BeTreAdd: int32(growCfg.Betreadd), //受疗加成% cfg.GamePropertyType_SuckBlood_Per: int32(growCfg.Suckblood), //吸血加成% } if hero.Id != "" { // objID 为空表示是怪物对象 不享受天赋属性加成 this.resetTalentProperty(hero) this.module.moduleHoroscope.ComputeHeroNumeric(hero.Uid, hero) } this.resetJuexingProperty(hero) this.calFigthValue(hero) } func (this *ModelHero) cleanData(uid string) { userList := this.module.GetHeroList(uid) for _, v := range userList { if err := this.DelListlds(uid, []string{v.Id}); err != nil { this.module.Errorf("cleanData err:%v", err) } } } func (this *ModelHero) AddCardExp(session comm.IUserSession, heros []*pb.DBHero, exp int32, model *db.DBModel) (curAddExp map[string]int32, award []*cfg.Gameatn, errdata *pb.ErrorData) { var ( tasks []*pb.BuriedParam changeupdate map[string]interface{} = make(map[string]interface{}) maxlvhero *pb.DBHero upwardconf *cfg.GameHeroLeveluprewardData upwardconfs []*cfg.GameHeroLeveluprewardData err error ) curAddExp = make(map[string]int32, len(heros)) for _, hero := range heros { var ( user *pb.DBUser expConf *cfg.GamePlayerlvData heroconf *cfg.GameHeroData preLv int32 //加经验之前的等级 curExp int32 // 加经验之后的经验 curLv int32 // 加经验之后的等级 update map[string]interface{} // 属性变化 ) if hero == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_HeroNoExist, Title: pb.ErrorCode_HeroNoExist.ToString(), } return } if hero.HeroID == "" { // 这里出bug了 this.module.Errorf("获取英雄数据出问题.玩家id:%s 英雄对象:%v", session.GetUserId(), hero) continue } update = make(map[string]interface{}, 0) curExp = hero.Exp curLv = hero.Lv preLv = curLv var maxLv int32 // 校验等级达到上限 if maxLv, err = this.module.configure.GetHeroMaxLv(hero.Star); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Message: fmt.Sprintf("cid:%s id:%s err:%s", hero.HeroID, hero.Id, err.Error()), } return } // 校验玩家等级 if user, err = this.module.GetUserForSession(session); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Message: err.Error(), } return } if expConf, err = this.module.configure.GetPlayerlvConf(user.Lv); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Message: err.Error(), } return } if maxLv > expConf.HeroLv { maxLv = expConf.HeroLv // 英雄最大等级限制 } _data := this.module.configure.GetHeroLv(curLv) if _data == nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), } return } if heroconf, err = this.module.configure.GetHeroConfig(hero.HeroID); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Message: err.Error(), } return } var maxExp int32 maxExp = _data.Heroexp if maxLv <= curLv && curExp >= maxExp { // 加经验之前校验是否达到最大等级 curAddExp[hero.Id] = 0 this.module.Debugf("英雄已经满级 不需要升级heroid:%s,addexp:%d", hero.Id, exp) return } var fullexp int32 // 溢出的经验 curExp += exp // 先把经验加上 for { // 死循环判断一键升级 if _data.Heroexp == 0 { fullexp = (curExp - maxExp) //curAddExp[hero.Id] = exp - (curExp - maxExp) // 减去超过部分的经验 curExp = 0 break } maxExp = _data.Heroexp if maxLv <= curLv && curExp >= maxExp { // 设置最大经验和等级 fullexp = (curExp - maxExp) //curAddExp[hero.Id] = exp - (curExp - maxExp) // 减去超过部分的经验 curLv = maxLv curExp = maxExp break } if maxExp > curExp { // 经验不够升级则不能执行升级操作 break } else { // 升级操作 curExp -= maxExp curLv += 1 // 经验够了 那么等级+1 if upwardconf, err = this.module.configure.GetHeroLvUpWardData(heroconf.Star, curLv); err == nil { upwardconfs = append(upwardconfs, upwardconf) } _data = this.module.configure.GetHeroLv(curLv) if _data == nil { // 等级加失败了 回到原来的等级 fullexp = (curExp - maxExp) curLv -= 1 break } } } if curAddExp[hero.Id] == 0 { curAddExp[hero.Id] = exp // 真正加的经验 } else { curAddExp[hero.Id] = (exp - fullexp) } this.module.Debugf("add hero exp :old lv:%d,old exp:%d,new lv:%d,new exp:%d,addexp:%d", hero.Lv, hero.Exp, curLv, curExp, exp) update["lv"] = curLv update["exp"] = curExp hero.Lv = curLv hero.Exp = curExp if curLv-preLv > 0 { // 升级了 统计任务 if maxlvhero == nil || curLv > maxlvhero.Lv { maxlvhero = hero } this.PropertyCompute(hero) update["property"] = hero.Property update["horoscopeProperty"] = hero.HoroscopeProperty update["talentProperty"] = hero.TalentProperty update["juexProperty"] = hero.JuexProperty update["fightvalue"] = hero.Fightvalue } changeupdate[hero.Id] = update if curLv-preLv > 0 { // 升级了 统计任务 tasks = append(tasks, comm.GetBuriedParam(comm.Rtype147, utils.ToInt32(hero.HeroID), curLv-preLv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype113, curLv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype4, hero.Lv, utils.ToInt32(hero.HeroID))) tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype23, hero.HeroID, hero.Star, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype24, curLv-preLv)) // szTask = append(szTask, comm.GetBuriedParam(comm.Rtype29, 1, hero.Lv, utils.ToInt32(hero.HeroID))) tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype23, hero.HeroID, hero.Star, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype32, hero.HeroID, heroconf.Color, hero.Lv)) //xx英雄满级、共鸣、觉醒至最高状态 nextAwaken, _ := this.module.configure.GetHeroAwakenConfig(hero.HeroID, hero.JuexingLv+1) if nextAwaken == nil { // 达到满级觉醒 var maxlv int32 if maxlv, err = this.module.configure.GetHeroMaxLv(hero.Star); err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_ConfigNoFound, Title: pb.ErrorCode_ConfigNoFound.ToString(), Message: fmt.Sprintf("cid:%s id:%s err:%s", hero.HeroID, hero.Id, err.Error()), } return } if hero.Lv == maxlv { var _l int32 talent, err := this.module.modelTalent.GetHerotalent(session.GetUserId()) if err == nil { for _, v := range talent { if v.HeroId == hero.HeroID { _l = int32(len(v.Talent)) break } } } if maxlv, e := this.module.configure.GetHeroTalentMaxLv(hero.HeroID); e == nil { if maxlv == _l { tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype37, hero.HeroID, heroconf.Color)) tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype38, hero.HeroID)) iHeroId, _ := strconv.Atoi(hero.HeroID) tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype243, hero.HeroID, int32(iHeroId))) } } } } tasks = append(tasks, comm.GetBuriedParam2(comm.Rtype111, hero.HeroID, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype112, 1, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype113, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype33, 1, 1, hero.Lv)) tasks = append(tasks, comm.GetBuriedParam(comm.Rtype118, hero.Lv, hero.JuexingLv)) } } if model != nil { if err := model.ChangeLists(session.GetUserId(), changeupdate); err != nil { this.module.Errorln(err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } } else { if err := this.ChangeLists(session.GetUserId(), changeupdate); err != nil { this.module.Errorln(err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Title: pb.ErrorCode_DBError.ToString(), Message: err.Error(), } return } } award = make([]*cfg.Gameatn, 0) if len(upwardconfs) > 0 { for _, v := range upwardconfs { award = append(award, v.Starup...) } } go this.module.AsynHandleSession(session.Clone(), func(session comm.IUserSession) { if maxlvhero != nil { this.module.passon.HeroUpLv(session, maxlvhero.HeroID, maxlvhero.Lv) } this.module.ModuleBuried.TriggerBuried(session, tasks...) }) return } // 玩家离线 清除缓存 func (this *ModelHero) RemoveUserHeroInfo(uid string) (err error) { //star := configure.Now() this.BatchDelLists(uid) //this.moduleHero.Debugf("=====%d,", time.Since(star).Milliseconds()) return } // 通过卡池的权重 获取英雄 func (this *ModelHero) GetRandHeroIdBypool(sz []int32) int32 { if len(sz) > 0 { var _totalW int64 // 总权重 var _tmpW int64 // 临时权重 for _, v := range sz { _totalW += int64(v) } // 随机权重 n, _ := rand.Int(rand.Reader, big.NewInt(_totalW)) for i, v := range sz { _tmpW += int64(v) if n.Int64() < _tmpW { // 种族保底卡池命中 return int32(i) } } } return 0 } // 初始化怪物属性 func (this *ModelHero) InitMonsterHero(heroCfgId string, star, lv int32) *pb.DBHero { heroCfg, _ := this.module.configure.GetHeroConfig(heroCfgId) if heroCfg == nil { this.module.Errorf("%v hero not found from config %v", heroCfgId) return nil } newHero := &pb.DBHero{ HeroID: heroCfg.Hid, Star: star, //初始星级 Lv: lv, //初始等级 Block: false, //未锁定 CardType: heroCfg.Type, //卡片类型 Skins: []int32{}, EquipID: make([]string, 8), //初始装备 AddProperty: make(map[int32]int32), Property: make(map[int32]int32), JuexProperty: make(map[int32]int32), TalentProperty: make(map[int32]int32), HoroscopeProperty: make(map[int32]int32), } this.initHeroSkill(newHero) this.PropertyCompute(newHero) return newHero } // 设置天赋属性 func (this *ModelHero) setTalentProperty(hero *pb.DBHero, conf *cfg.GameHeroTalentData) { if conf == nil || hero == nil { return } if hero.TalentProperty == nil { hero.TalentProperty = make(map[int32]int32) } hero.TalentProperty[conf.Attr.A] += conf.Attr.N _heroMap := make(map[string]interface{}, 0) _heroMap["talentProperty"] = hero.TalentProperty this.module.modelHero.calFigthValue(hero) _heroMap["fightvalue"] = hero.Fightvalue if err := this.ChangeList(hero.Uid, hero.Id, _heroMap); err != nil { this.module.Errorf("mergeenegryProperty err %v", err) } } // 重置天赋属性 func (this *ModelHero) cleanTalentProperty(hero *pb.DBHero) { if hero == nil { return } hero.TalentProperty = map[int32]int32{} hero.Talentskill = make([]*pb.SkillData, 0) // 重置技能 _heroMap := make(map[string]interface{}, 0) _heroMap["talentProperty"] = hero.TalentProperty _heroMap["talentskill"] = hero.Talentskill if err := this.ChangeList(hero.Uid, hero.Id, _heroMap); err != nil { this.module.Errorf("mergeenegryProperty err %v", err) } } // 重新计算天赋加成 attr hp atk def cri speed func (this *ModelHero) resetTalentProperty(hero *pb.DBHero) { if hero == nil { return } if rst, err := this.module.modelTalent.GetHerotalent(hero.Uid); err == nil { for _, v := range rst { if v.HeroId == hero.HeroID { // 找到对应的英雄 for k := range v.Talent { if conf, _ := this.module.configure.GetHeroTalent(k); conf != nil { //获取天赋 hero.TalentProperty[conf.Attr.A] = conf.Attr.N } } break } } } } // 创建一条英雄信息,如果有这个英雄 则转换成对应的碎片 func (this *ModelHero) createHero(session comm.IUserSession, heroCfgId string, count int32) (hero *pb.DBHero, atno []*pb.UserAtno, err error) { heros := make([]*pb.DBHero, 0) uid := session.GetUserId() heroCfg, _ := this.module.configure.GetHeroConfig(heroCfgId) bFirst := true if heroCfg == nil { err = errors.New("not found hero configID") this.module.Errorf("not found hero configID:%s", heroCfgId) return } if this.module.IsCross() { if dbModel, err1 := this.module.GetDBModelByUid(uid, this.TableName); err1 == nil { if err = dbModel.GetList(uid, &heros); err != nil { this.module.Errorf("err:%v", err) return } } else { this.module.Errorln(err) // 获取跨服对象失败 return } } else { if err = this.GetList(uid, &heros); err != nil { this.module.Errorf("err:%v", err) } } for _, obj := range heros { if obj.HeroID == heroCfgId { hero = obj bFirst = false atno = append(atno, &pb.UserAtno{ // 有英雄的时候 数量给0 A: "hero", T: hero.HeroID, N: 0, O: hero.Id, }) break } } if bFirst { // 没有当前英雄 count -= 1 hero, err = this.initHeroOverlying(uid, heroCfgId, 1) if err != nil { return } atno = append(atno, &pb.UserAtno{ A: "hero", T: hero.HeroID, N: 1, O: hero.Id, }) } res := make([]*cfg.Gameatn, 0) rst, err := this.module.ModuleUser.GetUserExpand(session.GetUserId()) if err != nil { return } bChange := false // 转碎片处理 for i := 0; int32(i) < count; i++ { bAdd := false //守护之星 获得 if heroCfg.Herofragnum > 0 { if v, ok := rst.Herofrag[hero.HeroID]; !ok { rst.Herofrag[hero.HeroID] = 1 bAdd = true bChange = true } else if heroCfg.Herofragnum > v { rst.Herofrag[hero.HeroID] += 1 bAdd = true bChange = true } } if bAdd { res = append(res, heroCfg.Herofrag...) for _, v := range heroCfg.Herofrag { atno = append(atno, &pb.UserAtno{ A: v.A, T: v.T, N: v.N, }) } } else { list := this.module.ModuleTools.GetGlobalConf().Moonshopmoney if list != nil { for pos, v := range list { if int32(pos)+3 == heroCfg.Star && v > 0 { res = append(res, &cfg.Gameatn{ A: "attr", T: "moongold", N: v, }) atno = append(atno, &pb.UserAtno{ A: "attr", T: "moongold", N: v, }) break } } } } bAdd = false // 初始化 // expitem 获得 if heroCfg.Expitemnum > 0 { if v, ok := rst.Expitem[hero.HeroID]; ok { if heroCfg.Expitemnum > v { rst.Expitem[hero.HeroID] += 1 bAdd = true bChange = true } } else { rst.Expitem[hero.HeroID] = 1 bAdd = true bChange = true } } if bAdd { res = append(res, heroCfg.Expitem...) for _, v := range heroCfg.Expitem { atno = append(atno, &pb.UserAtno{ A: v.A, T: v.T, N: v.N, }) } } } if bChange { this.module.ModuleUser.ChangeUserExpand(session.GetUserId(), map[string]interface{}{ "herofrag": rst.Herofrag, "expitem": rst.Expitem, }) } if len(res) > 0 { // 资源统一发放 this.module.DispenseRes(session, res, true) go this.module.AsynHandleSession(session.Clone(), func(session comm.IUserSession) { this.module.WriteUserLog(session.GetUserId(), heroCfgId, comm.GMResAddType, "create hero", res) }) } return } // 校验当前技能是否是满级 func (this *ModelHero) checkHeroAllSkillMax(hero *pb.DBHero) bool { for _, v := range hero.NormalSkill { if this.module.configure.GetHeroSkillMaxLvConfig(uint32(v.SkillID)) > v.SkillLv { return false } } return true } func (this *ModelHero) SetHeroFetterProperty(hero *pb.DBHero, attr []*cfg.Gameatr) { if hero == nil || len(attr) == 0 { return } if hero.Fetters == nil { hero.Fetters = make(map[int32]int32, 0) } for _, key := range attr { hero.Fetters[key.A] += key.N } } func (this *ModelHero) CheckDrawCardRes(session comm.IUserSession, drawConf *cfg.GameDrawPoolData, consume int32, drawCount int32) (costRes []*cfg.Gameatn, errdata *pb.ErrorData) { if consume == 0 { // 消耗A if drawCount == 1 { costRes = drawConf.ConsumeA // 单抽消耗 } else { costRes = drawConf.ConsumeA10 // 十连消耗 } } else { // 消耗B if drawCount == 1 { costRes = drawConf.ConsumeB // 单抽消耗 } else { costRes = drawConf.ConsumeB10 // 十连消耗 } } if errdata = this.module.CheckRes(session, costRes); errdata != nil { // 消耗数量不足直接返回 return } return } // 模拟获得英雄 (bImitate : true 表示模拟获得 并不发英雄) func (this *ModelHero) ImitateHeros(session comm.IUserSession, cids []string, bImitate bool) (addres [][]*cfg.Gameatn, add []*pb.DBHero, err error) { var ( szCard map[string]int32 bChange bool ) szCard = make(map[string]int32) heros := make([]*pb.DBHero, 0) uid := session.GetUserId() list := this.module.ModuleTools.GetGlobalConf().Moonshopmoney if list == nil { return } rst, err := this.module.ModuleUser.GetUserExpand(session.GetUserId()) if err != nil { return } if err = this.GetList(uid, &heros); err != nil { this.module.Errorf("err:%v", err) } for _, heroCfgId := range cids { var ( res []*cfg.Gameatn ) var hero *pb.DBHero heroCfg, _ := this.module.configure.GetHeroConfig(heroCfgId) bFirst := true if heroCfg == nil { err = errors.New("not found hero configID") this.module.Errorf("not found hero configID:%s", heroCfgId) return } szCard[heroCfgId] += 1 //统计卡片数量 for _, obj := range heros { if obj.HeroID == heroCfgId { hero = obj bFirst = false res = append(res, &cfg.Gameatn{ A: "hero", T: hero.HeroID, N: 0, }) break } } if bFirst { // 没有当前英雄 if bImitate { hero = this.InitHero(uid, heroCfgId) } else { hero, err = this.initHeroOverlying(uid, heroCfgId, 1) } if err != nil { return } res = append(res, &cfg.Gameatn{ A: "hero", T: hero.HeroID, N: 1, }) heros = append(heros, hero) add = append(add, hero) } // 转碎片处理 bAdd := false //守护之星 获得 if heroCfg.Herofragnum > 0 { if v, ok := rst.Herofrag[hero.HeroID]; !ok { rst.Herofrag[hero.HeroID] = 1 bAdd = true bChange = true } else if heroCfg.Herofragnum > v { rst.Herofrag[hero.HeroID] += 1 bAdd = true bChange = true } } if bAdd { res = append(res, heroCfg.Herofrag...) } else { for pos, v := range list { if int32(pos)+3 == heroCfg.Star && v > 0 { res = append(res, &cfg.Gameatn{ A: "attr", T: "moongold", N: v, }) break } } } bAdd = false // 初始化 // expitem 获得 if heroCfg.Expitemnum > 0 { if v, ok := rst.Expitem[hero.HeroID]; ok { if heroCfg.Expitemnum > v { rst.Expitem[hero.HeroID] += 1 bAdd = true bChange = true } } else { rst.Expitem[hero.HeroID] = 1 bAdd = true bChange = true } } if bAdd { res = append(res, heroCfg.Expitem...) } addres = append(addres, res) } if !bImitate && bChange { this.module.ModuleUser.ChangeUserExpand(session.GetUserId(), map[string]interface{}{ "herofrag": rst.Herofrag, "expitem": rst.Expitem, }) } if !bImitate { // 获得三消卡片资源数据 go this.module.AsynHandleSession(session.Clone(), func(session comm.IUserSession) { this.module.ModuleEntertain.AddXxlCard(session, szCard, true) }) } return }