package fishing import ( "math/rand" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/srvdata" "sync" "time" ) // FishArray 鱼阵 type FishArray struct { Type uint32 //鱼阵类型 Speed uint32 //鱼阵速度 Duration uint32 //持续时间 Fishs []*Fish //鱼阵中鱼 //Actions []*FishArrayAction //鱼阵动作 } // AppearFish 出鱼 type AppearFish struct { id uint64 //出鱼编号 aid uint32 //鱼阵编号 //mutex sync.Mutex //编号同步 start bool //是否出鱼 pause int64 //暂停时间 resumeTimer *time.Timer //恢复定时器 SceneEx *FishingSceneData appearFishs map[int32]*AppearFishConfig //出鱼策略 fishPath map[int32]*FishPath //出鱼路径配置 mutex sync.Mutex //编号同步 } type FishPath struct { PathId int32 AppearTime int32 DisappearTime int32 } type AppearFishConfig struct { fishId int32 //对应fish表中的fishType name string //鱼的名字 exp int32 //经验值 multiple []int32 //倍数 prob float64 //死亡概率 目前不用 看后期设计 每个场次单独控制 还是整体控制 baseRates float64 //基础概率 目前不用 path []int32 //出鱼路径 fishNum []int32 //出鱼数量 interval int32 //出鱼间隔 } // Start 开始 func (a *AppearFish) Start() { fishlogger.Trace("newFish 开始出鱼!!!!!!!!!!!!") a.aid = FishArrayOne //鱼阵起始标记 a.start = true //最短间隔 minInterval := int32(100000) for _, v := range base.FishOutEx.FishOutPool { if a.SceneEx.GetDBGameFree().GetSceneType() == v.SceneType && v.Interval < minInterval { minInterval = v.Interval } } //间隔差值 开始出鱼时候出鱼比较慢 让玩家早点看到屏幕鱼 var diffInterval int32 if minInterval > 1000 { diffInterval = minInterval - 1000 } //遍历出鱼 for _, v := range base.FishOutEx.FishOutPool { if a.SceneEx.GetDBGameFree().GetSceneType() == v.SceneType { tmp := v //定时出鱼 time.AfterFunc(time.Duration(tmp.Interval-diffInterval)*time.Millisecond, func() { a.do(tmp) }) } } /* //定时鱼阵 time.AfterFunc(time.Duration(FishArrayInterval)*time.Millisecond, func() { a.doArray() })*/ //定时切换场景 time.AfterFunc(FishArrayInterval, func() { a.cleanData() }) } // Stop 停止 func (a *AppearFish) Stop() { a.start = false } // Pause 暂停 func (a *AppearFish) Pause(t int64) { //暂停时间 a.pause = time.Now().Unix() a.pause += (t / 1000) //定时暂停 if a.resumeTimer != nil { a.resumeTimer.Stop() } a.resumeTimer = time.AfterFunc(time.Duration(t)*time.Millisecond, func() { a.resume() }) } // resume 恢复 func (a *AppearFish) resume() { a.pause = 0 fishlogger.Trace("暂停结束,恢复出鱼!") } // do 执行 func (a *AppearFish) do(afc *base.AppearFish) { if !a.start { return } startTime := time.Now().UnixNano() / int64(time.Millisecond) //定时出鱼 if a.pause != 0 { //不能出就不出不延迟至鱼阵结束 time.AfterFunc(time.Duration(afc.Interval)*time.Millisecond, func() { a.do(afc) }) return } //出鱼数量 quantity := afc.FishNum[0] if afc.FishNum[0] != afc.FishNum[1] { //随机出鱼数量 quantity += rand.Int31n(int32(afc.FishNum[1] - afc.FishNum[0] + 1)) } //创建出鱼切片 fishs := make([]*Fish, 0, quantity) for i := 0; i < int(quantity); i++ { //遍历鱼类 v := afc.FishId //获取鱼的配置 //conf := a.fishConfig[afc.fishId] conf := base.FishTemplateEx.FishPool[afc.FishId] if conf == nil { fishlogger.Errorf("出鱼 没有找到鱼的配置!!!!fishId = %v", afc.FishId) continue } //出鱼路径 出多条一样的鱼 路径尽量不重复 pathTime := time.Now().UnixNano() / int64(time.Millisecond) path := afc.Path[0] var num = 0 for { num++ if afc.Path[0] != afc.Path[1] { path += rand.Int31n(int32(afc.Path[1] - afc.Path[0] + 1)) } if a.PathUsable(path, fishs) && a.SceneEx.PathUsable(path) { break } path = afc.Path[0] } fishlogger.Tracef("寻找路径耗时:%v,循环了多少次:%v", time.Now().UnixNano()/int64(time.Millisecond)-pathTime, num) //创建出鱼 fish := new(Fish) //设置属性 fish.TemplateID = v fish.Path = path fish.Exp = conf.EXP //fish.SetrAppea(afc.FishAppearType) //计算倍数 待确认怎么随机 //策划让直接用鱼谱里的GOLD值 multiple := conf.Gold[0] if conf.Gold[0] != conf.Gold[1] { multiple += rand.Int31n(conf.Gold[1] - conf.Gold[0] + 1) } //设置属性 fish.DropCoin = multiple //这个参数是用于财神鱼 要不要待定 fish.MaxDropCoin = conf.Gold[1] fish.Speed = conf.Speed fish.Rate = conf.Rate fish.Name = conf.Name //设置出鱼编号 fish.FishID = int32(a.GetFishID()) fish.Event = afc.Event //不指定能打死自己的玩家 //fish.SetPlayer(InvalidPlayer) fishlogger.Infof("newfish 出鱼 fish = %v", fish) //加入切片 fishs = append(fishs, fish) } //桌子增加鱼 a.SceneEx.AddFish(fishs, 0) fishlogger.Trace("出鱼耗时:", time.Now().UnixNano()/int64(time.Millisecond)-startTime) //定时出鱼 time.AfterFunc(time.Duration(afc.Interval)*time.Millisecond, func() { a.do(afc) }) //通知客户端出鱼 a.SceneEx.NotifyAppearFish(fishs) } func (a *AppearFish) doPreArray() { if !a.start { return } //通知客户端 鱼潮来临 //a.pfacb() } // 鱼阵 doArray 执行 func (a *AppearFish) doArray() { /* if !a.start { return } //定时鱼阵 if a.pause != 0 { time.AfterFunc(time.Duration(a.GetPauseTime())*time.Second, func() { a.doArray() }) return } //最大持续时间 var maxDuration uint32 //创建鱼阵切片 var fishArrays []FishArray //子鱼阵编号 ids := CMIns().FishArrayConf[a.aid-1] a.aid = a.aid%FishArraySeven + 1 //遍历子鱼阵 for _, v := range ids { //创建鱼阵 var fishArray FishArray //获取鱼阵配置 fishArrayConfig := CMIns().GetFishArrayConfig(v) //遍历鱼阵组 for _, i := range fishArrayConfig.FishArrayGroups { //获取鱼类配置 conf := CMIns().GetFishConfig(i.FishType) if conf == nil { continue } //遍历鱼阵鱼 for _, j := range i.FishArrayFishs { //创建出鱼 fish := new(Fish) //计算倍数 multiple := conf.FishMinMultiple if conf.FishMinMultiple != conf.FishMaxMultiple { multiple += uint32(rand.Int31n(int32(conf.FishMaxMultiple - conf.FishMinMultiple + 1))) } //设置属性 fish.SetType(i.FishType) fish.SetMultiple(multiple) fish.SetProbability(conf.FishProbability) fish.SetLotteryProbability(conf.LotteryProbability) fish.SetName(conf.FishName) fish.SetAngle(j.FishAngle) fish.SetX(j.FishX) fish.SetY(j.FishY) //设置出鱼编号 fish.SetID(a.GetFishID()) //不指定能打死自己的玩家 fish.SetPlayer(InvalidPlayer) //加入切片 fishArray.Fishs = append(fishArray.Fishs, fish) } } //设置鱼阵属性 fishArray.Type = fishArrayConfig.FishArrayType fishArray.Speed = fishArrayConfig.FishArraySpeed fishArray.Duration = fishArrayConfig.FishArrayDuration fishArray.Actions = fishArrayConfig.FishArrayActions //最高持续时间 if maxDuration < fishArrayConfig.FishArrayDuration { maxDuration = fishArrayConfig.FishArrayDuration } //加入鱼阵切片 fishArrays = append(fishArrays, fishArray) } //清空鱼 a.table.ClearFish() //暂停出鱼 a.Pause(int64(maxDuration + 5000)) //增加鱼阵 a.table.AddFishArray(fishArrays) //定时鱼阵 time.AfterFunc(time.Duration(CMIns().FishArrayInterval)*time.Millisecond, func() { a.doArray() }) //time.AfterFunc(time.Duration(CMIns().FishArrayInterval-15)*time.Millisecond, func() { // a.doPreArray() //}) //设置标识 a.table.SetFishArray(true) //鱼阵回调 //通知客户端 a.facb(0, fishArrays) */ } /*// DeadFishArray 死鱼鱼阵 func (a *AppearFish) DeadFishArray(tp uint32, fid uint64) { //获取配置 conf := CMIns().GetFishConfig(tp) if conf == nil { return } //校验鱼类 if conf.DeadFish == 0 { return } //确定鱼类 fishType := conf.DeadFish redFishType := conf.DeadRedFish //获取鱼类配置 fishconfig := CMIns().GetFishConfig(fishType) if fishconfig == nil { return } //创建鱼阵切片 var fishArrays []FishArray //随机红鱼位置 index := int(rand.Int31n(int32(NumberPreCircle))) //获取红鱼配置 redFishConfig := CMIns().GetFishConfig(redFishType) //发散三圈 for i := 0; i < CircleNumber; i++ { //创建鱼阵 var fishArray FishArray for j := 0; j < NumberPreCircle; j++ { //创建出鱼 fish := new(Fish) //红鱼属性 if i == 2 && j == index && redFishConfig != nil { //计算倍数 multiple := redFishConfig.FishMinMultiple if redFishConfig.FishMinMultiple != redFishConfig.FishMaxMultiple { multiple += uint32(rand.Int31n(int32(redFishConfig.FishMaxMultiple - redFishConfig.FishMinMultiple + 1))) } //设置属性 fish.SetType(redFishType) fish.SetMultiple(multiple) fish.SetProbability(redFishConfig.FishProbability) fish.SetLotteryProbability(redFishConfig.LotteryProbability) fish.SetName(redFishConfig.FishName) } else { //计算倍数 multiple := fishconfig.FishMinMultiple if fishconfig.FishMinMultiple != fishconfig.FishMaxMultiple { multiple += uint32(rand.Int31n(int32(fishconfig.FishMaxMultiple - fishconfig.FishMinMultiple + 1))) } //设置属性 fish.SetType(fishType) fish.SetMultiple(multiple) fish.SetProbability(fishconfig.FishProbability) fish.SetLotteryProbability(fishconfig.LotteryProbability) fish.SetName(fishconfig.FishName) } fish.SetAngle((float32(360) / float32(NumberPreCircle)) * float32(j)) //设置出鱼编号 fish.SetID(a.GetFishID()) //不指定能打死自己的玩家 fish.SetPlayer(InvalidPlayer) //加入切片 fishArray.Fishs = append(fishArray.Fishs, fish) } //设置鱼阵属性 fishArray.Type = FishArrayDisperse fishArray.Speed = CMIns().FishArrays[17+i].FishArraySpeed fishArray.Duration = CMIns().FishArrays[17+i].FishArrayDuration //fishArray.Actions = CMIns().FishArrays[17+i].FishArrayActions //加快死鱼鱼阵出圈速度 fishArrayAction := &FishArrayAction{ Path: CMIns().FishArrays[17+i].FishArrayActions[0].Path, Time: CMIns().FishArrays[17+i].FishArrayActions[0].Time / 2, } fishArray.Actions = append(fishArray.Actions, fishArrayAction) fishArray.Actions = append(fishArray.Actions, CMIns().FishArrays[17+i].FishArrayActions[1]) //加入鱼阵切片 fishArrays = append(fishArrays, fishArray) } //增加鱼阵 a.table.AddFishArray(fishArrays) //通知客户端鱼阵消息 a.facb(fid, fishArrays) } */ //==================== //simple interface //==================== // GetID 出鱼编号 func (a *AppearFish) GetID() uint64 { return a.id } // GetAID 鱼阵编号 func (a *AppearFish) GetAID() uint32 { return a.aid } // IsStart 是否开始 func (a *AppearFish) IsStart() bool { return a.start } // IsPause 是否暂停 func (a *AppearFish) IsPause() bool { return a.pause != 0 } // GetFishID 获取出鱼编号 func (a *AppearFish) GetFishID() uint64 { a.mutex.Lock() defer a.mutex.Unlock() a.id++ return a.id } // GetPauseTime 获取暂停时间 func (a *AppearFish) GetPauseTime() int64 { surplus := a.pause - time.Now().Unix() if surplus <= 0 { surplus = 1 } return surplus } // PathUsable 路径可用 func (a *AppearFish) PathUsable(path int32, fishs []*Fish) bool { for _, v := range fishs { if v.Path == path { return false } } return true } // 鱼潮策略初始化 func (a *AppearFish) InitFishArray() { //后续再做 } // 初始化鱼的路径 func (a *AppearFish) InitFishPath() { a.fishPath = make(map[int32]*FishPath) for _, v := range srvdata.PBDB_FishPathMgr.Datas.Arr { a.fishPath[v.Id] = &FishPath{ PathId: v.Id, AppearTime: v.AppearTime, DisappearTime: v.DisappearTime, } } } // 清理数据 func (a *AppearFish) cleanData() { //重置出鱼编号 a.id = 0 //重置场景里的鱼 a.SceneEx.fish_list = make(map[int32]*Fish) // 鱼标识 存活的鱼 //重置逻辑帧 a.SceneEx.TimePoint = 0 fishlogger.Trace("定时切换场景,清理数据!!!!!!!!") //通知客户端切换场景 a.SceneEx.NotifyChangeScene() //定时切换场景 time.AfterFunc(FishArrayInterval, func() { if a.start { a.cleanData() } }) }