package fishing import ( "fmt" "math" "math/rand" "strconv" "strings" "sync" "time" "github.com/cihub/seelog" "mongo.games.com/goserver/core" "mongo.games.com/goserver/core/netlib" "mongo.games.com/goserver/core/timer" "mongo.games.com/goserver/srvlib/action" srvlibproto "mongo.games.com/goserver/srvlib/protocol" "mongo.games.com/game/common" "mongo.games.com/game/gamerule/fishing" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/model" "mongo.games.com/game/proto" fishing_proto "mongo.games.com/game/protocol/fishing" "mongo.games.com/game/srvdata" ) var fishlogger seelog.LoggerInterface func init() { core.RegisteHook(core.HOOK_BEFORE_START, func() error { fishlogger = common.GetLoggerInstanceByName("FishLogger") return nil }) } type FishBattle struct { SnId int32 // 玩家id Bullet int32 // 子弹id Power int32 // 炮台倍率 FishsId []int // 被打鱼id ExtFishis []int32 // 关联鱼id LockFish int32 // 用来提交捕捉到的指定选鱼(天天捕鱼) Multiple int32 //子弹倍数 } type Bullet struct { Id int32 Power int32 SrcId int32 LifeTime int32 Multiple int32 } type FishingSceneData struct { *base.Scene players map[int32]*FishingPlayerData seats [fishing.MaxPlayer]*FishingPlayerData BattleBuff chan *FishBattle TimePoint int32 // 帧同步中的帧序号,这里一帧是100毫秒 NextTime int64 // 下次模式切换的时间点 fish_list map[int32]*Fish // 鱼标识 存活的鱼 delFish_list map[int32]int32 // 鱼标识:1 打死的鱼 fish_Event map[int32][]int32 // 事件id:鱼标识;鱼消失时要同步维护 fishLevel int32 // 场次 frozenTick int32 // 冰冻计时 lastTick int64 // 鱼同步计时 remainder int64 // 鱼同步计时 lastBossTime int64 // boss 上一次出现的时间 lastLittleBossTime int64 // 小boss 上一次出现的时间 BossId int32 //当前场景的BOSS BossTag int32 //当前场景BOSS是否 LastID int32 //当前场景鱼ID生成器 hDestroy timer.TimerHandle fishsMutex sync.Mutex //同步鱼 af AppearFish // 出鱼管理 platform string gameId int sceneType int sceneMode int keyGameId string //游戏ID testing bool gamefreeId int32 groupId int32 agentor int32 fluctuateMaxMap map[string]float64 ChangeSceneId int32 //切换场景Id 客户端用 } func NewFishingSceneData(s *base.Scene) *FishingSceneData { return &FishingSceneData{ Scene: s, players: make(map[int32]*FishingPlayerData), BattleBuff: make(chan *FishBattle, 1000), fish_list: make(map[int32]*Fish), fish_Event: make(map[int32][]int32), delFish_list: make(map[int32]int32), fluctuateMaxMap: make(map[string]float64), } } func (this *FishingSceneData) RebindPlayerSnId(oldSnId, newSnId int32) { if p, exist := this.players[oldSnId]; exist { delete(this.players, oldSnId) this.players[newSnId] = p } } func (this *FishingSceneData) init() bool { if this.GetDBGameFree() != nil { this.fishLevel = this.GetDBGameFree().GetSceneType() // 更新当前的场次 } this.SetPlayerNum(4) this.gameId = this.GetGameId() this.platform = this.GetPlatform() this.sceneType = int(this.GetDBGameFree().GetSceneType()) this.keyGameId = this.GetKeyGameId() this.testing = this.GetTesting() this.gamefreeId = this.GetGameFreeId() this.groupId = this.GetGroupId() this.sceneMode = this.GetSceneMode() this.TimePoint = 0 this.lastLittleBossTime = time.Now().Unix() this.lastBossTime = time.Now().Unix() /* //随机一个初始点 start := rand.Int31n(this.MaxTick * 4 / 5) for i := int32(0); i < start; i++ { this.fishFactory() }*/ this.af.SceneEx = this //this.NextTime -= int64(time.Millisecond * time.Duration(start*100)) fluctuateMaxStr := this.GetDBGameFree().FluctuateMax if len(fluctuateMaxStr) > 0 { pairs := strings.Split(fluctuateMaxStr, ";") for _, pair := range pairs { keyValue := strings.Split(pair, ",") key := keyValue[0] value, _ := strconv.ParseFloat(keyValue[1], 64) this.fluctuateMaxMap[key] = value } } //this.af.InitFishAppear() this.af.InitFishPath() this.af.Start() return true } func (this *FishingSceneData) Clean() { for _, p := range this.players { //5款捕鱼保持一致 fishID, coin, taxc := int32(0), int32(0), int64(0) for _, v := range p.bullet { coin += v.Power taxc += int64(float64(this.GetDBGameFree().GetTaxRate()) / 10000 * float64(v.Power)) } this.RetBulletCoin(p, fishID, coin, taxc, false) // 合并后发送 p.bullet = make(map[int32]*Bullet) p.BulletLimit = [BULLETLIMIT]int64{} p.fishEvent = make(map[string]*FishingPlayerEvent) p.logFishCount = make(map[int64]*model.FishCoinNum) } this.fish_list = make(map[int32]*Fish) this.delFish_list = make(map[int32]int32) this.fish_Event = make(map[int32][]int32) } func (this *FishingSceneData) BroadcastPlayerLeave(p *base.Player, reason int) { } func (this *FishingSceneData) SceneDestroy(force bool) { this.Scene.Destroy(force) } // RetBulletCoin 返还子弹消耗的金币 // 子弹碰撞的鱼已经死了或者过期了,返还 func (this *FishingSceneData) RetBulletCoin(player *FishingPlayerData, fishID, coin int32, taxc int64, flag bool) { if player.IsRob && !model.GameParamData.IsRobFightTest { return } pack := &fishing_proto.SCFishDel{ FishId: proto.Int32(int32(fishID)), Coin: proto.Int32(coin), CurrentPlayerCoin: proto.Int64(player.CoinCache), } proto.SetDefaults(pack) if !this.GetTesting() && !player.IsRob { //所有捕鱼统一 player.NewStatics(int64(-coin), 0) } //taxc := int64(float64(this.GetDBGameFree().GetTaxRate()) / 10000 * float64(coin)) player.LostCoin -= int64(coin) player.CoinCache += int64(coin) player.SetTotalBet(player.GetTotalBet() - int64(coin)) //player.Statics(this.KeyGameId, this.KeyGamefreeId, int64(coin), false) player.LastRechargeWinCoin -= int64(coin) if !this.GetTesting() { player.taxCoin -= float64(taxc) player.sTaxCoin -= float64(taxc) } fishlogger.Trace("RetBulletCoin : ", fishID, player.IsRob, coin, player.LostCoin, player.CoinCache, player.GetTotalBet()) //base.GetCoinPoolMgr().PopCoin(this.GetGameFreeId(), this.GetGroupId(), this.GetPlatform(), int64(coin)-taxc) tax := base.GetCoinPoolMgr().GetTax() base.GetCoinPoolMgr().SetTax(tax - float64(taxc)) pack.CurrentPlayerCoin = proto.Int64(player.CoinCache) player.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_FISHDEL), pack) } /* * 玩家相关 */ func (this *FishingSceneData) EnterPlayer(player *FishingPlayerData) bool { pos := -1 emptyPos := []int{} for i := 0; i < fishing.MaxPlayer; i++ { if this.seats[i] == nil { emptyPos = append(emptyPos, i) } } if len(emptyPos) > 0 { pos = emptyPos[common.RandInt(len(emptyPos))] } else { fishlogger.Error("Fishing enter player find pos error.") } player.SetPos(pos) player.CoinCache = player.GetCoin() player.LostCoin = 0 player.LostCoinCache = 0 //player.FishPoolKey = fmt.Sprintf("%v-%v", this.GetGameFreeId(), player.Platform) this.players[player.SnId] = player this.seats[pos] = player this.OnEnterPlayer(player) return true } func (this *FishingSceneData) OnEnterPlayer(player *FishingPlayerData) { /* 如果进场的是机器人,寻找场内负载最小的玩家进行绑定 如果进场的是玩家,寻找场内没有代理的机器人 */ var tempPlayer *FishingPlayerData //新逻辑 if player.IsRob { for i := 0; i < fishing.MaxPlayer; i++ { curSeatPlayer := this.seats[i] if curSeatPlayer != nil && !curSeatPlayer.IsRob { //新逻辑 if tempPlayer == nil { tempPlayer = curSeatPlayer } else if len(tempPlayer.RobotSnIds) > len(curSeatPlayer.RobotSnIds) { tempPlayer = curSeatPlayer } //老逻辑 if curSeatPlayer.AgentParam == 0 { curSeatPlayer.AgentParam = player.SnId player.AgentParam = curSeatPlayer.SnId curSeatPlayer.RobotSnIds = append(curSeatPlayer.RobotSnIds, player.SnId) break } } } //新逻辑 设置机器人的代理情况 if tempPlayer != nil && player.AgentParam == 0 { player.AgentParam = tempPlayer.SnId tempPlayer.AgentParam = player.SnId tempPlayer.RobotSnIds = append(tempPlayer.RobotSnIds, player.SnId) } } else { for i := 0; i < fishing.MaxPlayer; i++ { curSeatRobot := this.seats[i] if curSeatRobot != nil && curSeatRobot.IsRob { if curSeatRobot.AgentParam == 0 { //无主机器人 curSeatRobot.AgentParam = player.SnId player.AgentParam = curSeatRobot.SnId player.RobotSnIds = append(player.RobotSnIds, curSeatRobot.SnId) //新逻辑 } } } if len(player.RobotSnIds) == 0 { for i := 0; i < fishing.MaxPlayer; i++ { curSeatRobot := this.seats[i] if curSeatRobot != nil && curSeatRobot.IsRob { if curSeatRobot.AgentParam != 0 { //需要重新平衡下机器人负载 for j := 0; j < fishing.MaxPlayer; j++ { curSeatPlayer := this.seats[j] if curSeatPlayer != nil && !curSeatPlayer.IsRob && curSeatPlayer.SnId == curSeatRobot.AgentParam && len(curSeatPlayer.RobotSnIds) > 1 { //bind agent curSeatRobot.AgentParam = player.SnId player.AgentParam = curSeatRobot.SnId player.RobotSnIds = append(player.RobotSnIds, curSeatRobot.SnId) //unbind agent curSeatPlayer.RobotSnIds = common.DelSliceInt32(curSeatPlayer.RobotSnIds, curSeatRobot.SnId) curSeatPlayer.AgentParam = curSeatPlayer.RobotSnIds[0] break } } } } //分担一个就可以了 if len(player.RobotSnIds) != 0 { break } } } } return } func (this *FishingSceneData) QuitPlayer(player *FishingPlayerData, reason int) bool { if _, ok := this.players[player.SnId]; ok { player.SetSelVip(this.KeyGameId) player.SaveDetailedLog(this.Scene) delete(this.players, player.SnId) this.seats[player.GetPos()] = nil this.BroadcastPlayerLeave(player.Player, 0) diffCoin := player.CoinCache - player.GetCoin() player.AddCoin(diffCoin, common.GainWay_Fishing, base.SyncFlag_ToClient, "system", this.GetSceneName()) if diffCoin != 0 || player.LostCoin != 0 { if !player.IsRob && !this.GetTesting() { player.AddServiceFee(int64(player.taxCoin)) } player.SetGameTimes(player.GetGameTimes() + 1) if diffCoin > 0 { //player.winTimes++ player.SetWinTimes(player.GetWinTimes() + 1) } else { //player.lostTimes++ player.SetLostTimes(player.GetLostTimes() + 1) } } this.OnQuitPlayer(player, reason) return true } else { return false } } func (this *FishingSceneData) OnQuitPlayer(player *FishingPlayerData, reason int) { /* 如果离场的是机器人,从代理玩家身上将其删除 如果离场的是玩家,为玩家身上代理的机器人寻找其他代理 */ if player.IsRob { //机器人离场 for i := 0; i < fishing.MaxPlayer; i++ { curSeatPlayer := this.seats[i] if curSeatPlayer != nil && !curSeatPlayer.IsRob { //老逻辑,不改动 if curSeatPlayer.AgentParam == player.SnId { curSeatPlayer.AgentParam = 0 player.AgentParam = 0 } //新逻辑 if common.InSliceInt32(curSeatPlayer.RobotSnIds, player.SnId) { curSeatPlayer.RobotSnIds = common.DelSliceInt32(curSeatPlayer.RobotSnIds, player.SnId) player.AgentParam = 0 if len(curSeatPlayer.RobotSnIds) > 0 { curSeatPlayer.AgentParam = curSeatPlayer.RobotSnIds[0] } else { curSeatPlayer.AgentParam = 0 } } } } } else { //玩家离场 for i := 0; i < fishing.MaxPlayer; i++ { curSeatRobot := this.seats[i] if curSeatRobot != nil && curSeatRobot.IsRob { if curSeatRobot.AgentParam == player.SnId { curSeatRobot.AgentParam = 0 player.AgentParam = 0 var tempPlayer *FishingPlayerData //新逻辑 负载最小的玩家 for j := 0; j < fishing.MaxPlayer; j++ { curSeatPlayer := this.seats[j] if curSeatPlayer != nil && !curSeatPlayer.IsRob && curSeatPlayer != player { if curSeatPlayer.AgentParam == 0 { curSeatPlayer.AgentParam = curSeatRobot.SnId curSeatRobot.AgentParam = curSeatPlayer.SnId curSeatPlayer.RobotSnIds = append(curSeatPlayer.RobotSnIds, curSeatRobot.SnId) //新逻辑 pack := &fishing_proto.SCReBindAgent{ PlayerSnid: proto.Int32(curSeatPlayer.SnId), RobSnid: proto.Int32(curSeatRobot.SnId), } curSeatPlayer.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_REBINDAGENT), pack) break } else { if tempPlayer == nil { tempPlayer = curSeatPlayer } else if len(tempPlayer.RobotSnIds) > len(curSeatPlayer.RobotSnIds) { tempPlayer = curSeatPlayer } } } } //新逻辑 if tempPlayer != nil && curSeatRobot.AgentParam == 0 { curSeatRobot.AgentParam = tempPlayer.SnId tempPlayer.AgentParam = curSeatRobot.SnId tempPlayer.RobotSnIds = append(tempPlayer.RobotSnIds, curSeatRobot.SnId) pack := &fishing_proto.SCReBindAgent{ PlayerSnid: proto.Int32(tempPlayer.SnId), RobSnid: proto.Int32(curSeatRobot.SnId), } tempPlayer.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_REBINDAGENT), pack) } } } } player.RobotSnIds = nil } } func (this *FishingSceneData) OnTick() { if this.TimePoint%10 == 0 { // TimePoint单位是百毫秒,所以是每秒执行一次 fishTimeOut() if this.frozenTick > 0 { this.frozenTick -= 1 fishlogger.Trace("当前屏幕冰冻剩余时间:", this.frozenTick) } this.FishTimeOut() //检测技能CD this.CheckSkillCD() } } func (this *FishingSceneData) CheckSkillCD() { for _, player := range this.players { /* player.SkillMutex.Lock() defer player.SkillMutex.Unlock()*/ delSkillCD := []int32{} for skillId, endTime := range player.SkillCd { if time.Now().UnixNano()/int64(time.Millisecond) >= endTime { delSkillCD = append(delSkillCD, skillId) } } //删除技能cd for _, key := range delSkillCD { delete(player.SkillCd, key) } delSkillGCD := []int32{} for skillId, endTime := range player.SkillGCD { if time.Now().UnixNano()/int64(time.Millisecond) >= endTime { delSkillGCD = append(delSkillCD, skillId) } } //删除公共CD for _, key := range delSkillGCD { delete(player.SkillGCD, key) } } } // 获取当前场景是否存在世界BOSS func (this *FishingSceneData) GetWorldBoss() bool { for _, value := range this.fish_list { if value.FishType == fishing.WorldBoss { return true } } return false } // fishTimeOut 清除过期的鱼 func (this *FishingSceneData) FishTimeOut() { //设置鱼的创建帧和结束帧 this.fishsMutex.Lock() defer this.fishsMutex.Unlock() for key, value := range this.fish_list { if value == nil { delete(this.fish_list, key) fishlogger.Tracef("[fishTimeOut]1 delete fish:[%v]", key) continue } if value.LiveTick <= this.TimePoint { delete(this.fish_list, key) fishlogger.Tracef("[fishTimeOut]2 delete fish:[%v]", key) if value.Event != 0 { this.fish_Event[value.Event] = common.DelSliceInt32(this.fish_Event[value.Event], value.FishID) } } } } func (this *FishingSceneData) AddFish(fishs []*Fish, duration int32) { //设置鱼的创建帧和结束帧 this.fishsMutex.Lock() defer this.fishsMutex.Unlock() for _, fish := range fishs { fish.BirthTick = this.TimePoint path := this.af.fishPath[fish.Path] if duration == 0 { fish.InitCrashDetect(0, path) } fish.LiveTick += this.TimePoint fishlogger.Tracef("计算鱼的结束帧 liveTick = %v,当前场景帧:%v", fish.LiveTick, this.TimePoint) this.fish_list[fish.FishID] = fish if fish.Event != 0 { eventFishs := this.fish_Event[fish.Event] if eventFishs == nil { eventFishs = []int32{} } this.fish_Event[fish.Event] = append(eventFishs, fish.FishID) fishlogger.Trace("出鱼 添加鱼事件!!! fishType = %v,fishId = %v", fish.FishType, fish.FishID) } } } func (this *FishingSceneData) DelFish(id int32) { //加锁管理 this.fishsMutex.Lock() defer this.fishsMutex.Unlock() if _, exist := this.fish_list[id]; exist { delete(this.fish_list, id) //fishlogger.Tracef("[DelFish] delete fish:[%v]", id) this.delFish_list[id] = 1 } } // notifyAppearFish 通知出鱼 func (this *FishingSceneData) NotifyAppearFish(fishs []*Fish) { //创建队列 array := make([]*fishing_proto.FishInfo, 0, len(fishs)) //遍历出鱼 for _, v := range fishs { fish := &fishing_proto.FishInfo{ FishID: v.FishID, FishType: v.FishType, FishPath: v.Path, FishSpeed: v.Speed, BirthTick: v.BirthTick, LiveTick: v.LiveTick, FishChild: v.Child, } //加入队列 array = append(array, fish) } //构造数据 appearFish := &fishing_proto.SCNotifyAppearFish{ OutFishType: 1, Fishs: array, } //发送数据 this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_NOTIFYAPPEARFISH), appearFish, 0) fishlogger.Trace("通知客户端出鱼!!!!!!!!!!!!!!!!!appearFish = ", appearFish) } // 通知客户端切换场景 func (this *FishingSceneData) NotifyChangeScene() { this.ChangeSceneId += 1 if this.ChangeSceneId >= ChangeSceneIdMax { this.ChangeSceneId = 0 } date := &fishing_proto.SCNotifyChangeScene{ SceneId: this.ChangeSceneId, } this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_NOTIFYCHANGESCENE), date, 0) fishlogger.Trace("通知客户端切换场景并清空数据!!!!!!") } /* * 捕鱼相关 */ func (this *FishingSceneData) fishBattle() { select { case data := <-this.BattleBuff: player := this.players[data.SnId] if player == nil { fishlogger.Tracef("Bullet %v owner %v offline.", data.Bullet, data.SnId) return } delete(player.bullet, data.Bullet) // 二次清楚 防止没有删掉 var count = len(data.FishsId) if count > 0 && data.Power > 0 { this.fishProcess(player, data.FishsId, data.Power, data.Multiple, data.ExtFishis) } default: break } } // fishProcess 捕鱼击中的标准处理逻辑 // fishIds 被击中的鱼(目前只会是一条鱼) // power 炮倍率 // extfishis 关联鱼 func (this *FishingSceneData) fishProcess(player *FishingPlayerData, fishIds []int, power, multiple int32, extfishis []int32) { if len(fishIds) == 0 { return } //调试辅助 sendMiss := func(fishid, rate int32) { if player.GMLevel > 0 { pack := &fishing_proto.SCFireMiss{ FishId: proto.Int32(fishid), Rate: proto.Int32(rate), } proto.SetDefaults(pack) player.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_FIREMISS), pack) } } // 去重,检查存活 extFishMap := make(map[int32]struct{}) dropcoinext := int32(0) // 掉落金币 for _, v := range extfishis { if _, exist := extFishMap[v]; !exist { extFishMap[v] = struct{}{} var extfish = this.fish_list[v] if extfish == nil { continue } dropcoinext += extfish.DropCoin } } var killRate int32 var death bool var robot = player.IsRob var ts = time.Now().Unix() hitFishMap := make(map[int32]struct{}) for _, id := range fishIds { hitFishMap[int32(id)] = struct{}{} } for value, _ := range hitFishMap { var fish = this.fish_list[value] // 取出对应的鱼的概率 // 判断当前的鱼是否有效 if fish == nil { fishlogger.Tracef("[fishProcess] Be hit fish [%v] is disappear.", value) taxc := int64(float64(this.GetDBGameFree().GetTaxRate()) / 10000 * float64(power)) if player.powerType != FreePowerType { // 不是免费炮期间返还 this.RetBulletCoin(player, int32(value), power, taxc, true) } //} //鱼不存在 sendMiss(int32(value), -1) continue } //特殊鱼处理 if fish.TemplateID == fishing.Fish_CaiShen && fish.DropCoin < fish.MaxDropCoin { fish.DropCoin++ this.syncFishCoin(fish) } //同组的鱼(一网打尽) var groupcoinex int32 if fish.Event > 0 && fish.Event <= fishing.Event_Group_Max { groupFishs := this.fish_Event[fish.Event] for _, fishId := range groupFishs { if fishId == value { //去重 continue } if _, exist := extFishMap[value]; exist { //去重 continue } fishg := this.fish_list[fishId] if fishg == nil { continue } if fishg.IsDeath(this.TimePoint) { continue } if !fishg.IsBirth(this.TimePoint) { continue } groupcoinex += fishg.DropCoin } } //判断鱼是不是boss鱼 1 普通BOSS 2 世界BOSS if fish.IsBoss == fishing.Boss { //增加BOSS奖池 this.AddBossPond(player, fish.TemplateID, power) } death = false if (robot && !model.GameParamData.IsRobFightTest) || this.GetTesting() { //体验场概率稍有提升 killRate = 10000 / (fish.DropCoin + dropcoinext + groupcoinex) if this.GetTesting() { killRate *= 2 } if rand.Int31n(10000) < killRate { death = true } // todo 强制设置机器人 鱼死不 (测试使用) //death = false } else { //欢乐捕鱼|李逵劈鱼...其他捕鱼都走这个算法 // start 记录相关鱼的击中次数 key := player.MakeLogKey(fish.TemplateID, power) if v, ok := player.logFishCount[key]; ok { v.HitNum++ } else { player.logFishCount[key] = &model.FishCoinNum{ HitNum: 1, ID: fish.TemplateID, Power: power, } } //击中计数 player.logBulletHitNums++ //判断鱼是否死亡 dto := this.isDead(player, value, power, multiple, fish.DropCoin, 0, false) death = dto.IsResult } if !death { //鱼没死 sendMiss(int32(value), killRate) continue } // 判断当前是否是 特殊鱼 deathFishs := this.fishEvent(fish, player, power, ts, extfishis) if len(deathFishs) == 0 { //鱼没死 sendMiss(int32(value), killRate) continue } this.fishSettlements(deathFishs, player, power, fish.Event, ts, 0, 0) } //写条记录 if player.logBulletHitNums >= CountSaveNums { player.SaveDetailedLog(this.Scene) } } type GameSettleDto struct { HitRate float64 Suiji float64 IsResult bool Rate interface{} } // 计算鱼死亡 func (this *FishingSceneData) isDead(player *FishingPlayerData, fishType int32, power int32, multiple int32, fishmu int32, totalfishProb float64, flag bool) *GameSettleDto { /** * 取反正切函数: ATAN(个人金币池的绝对值/(用户目前炮倍*炮数波动参数))/3.14*2*当前场次波动上限+1 */ //判断鱼死亡 // 获取鱼的配置信息和波动上限信息 var fish = this.fish_list[fishType] // 取出对应的鱼的概率 // 判断是否满足波动上限条件 glp := this.checkIsmeet(this.fluctuateMaxMap, fishmu) var fishProb float64 if !flag { // 如果不是标志位,使用鱼的默认概率 fishProb = float64(fish.Rate) / 10000.0 } else { // 否则使用总概率 fishProb = totalfishProb } // 计算炮的加成概率 canPro := float64(float64(power) * float64(this.GetDBGameFree().Fluctuate)) // 获取捕鱼最大负面影响、最大命中率上限值和个人金币池的绝对值 negativemax := float64(this.GetDBGameFree().NegativeMax) / 1000.0 catchFishratioMax := float64(this.GetDBGameFree().RatioMax) / 1000.0 scorepool := player.MoneyPond // 使用反正切函数计算命中率的变化率 glp1, error := strconv.ParseFloat(glp, 64) if error != nil { dto := &GameSettleDto{ IsResult: false, } return dto } rate := math.Atan(math.Abs(float64(scorepool))/canPro)/3.14*2*glp1 + 1 var hitRate float64 if scorepool > 0 { // 如果个人金币池大于0,则命中率为鱼的概率乘以变化率 hitRate = fishProb * rate } else { if rate > negativemax { // 如果变化率超过了捕鱼最大负面影响,将变化率限制为最大负面影响值 rate = negativemax } // 命中率为鱼的概率除以变化率,但不能超过最大命中率上限值 hitRate = fishProb / rate if hitRate > catchFishratioMax { hitRate = catchFishratioMax } } // 根据倍数随机判断命中次数 var suiji float64 isresult := false num := multiple // 如果玩家有特殊状态,则命中次数为2次 if player.powerType != 0 { num = 2 } for i := 0; i < int(num); i++ { // 使用随机数判断命中结果 suiji = rand.Float64() isresult = hitRate >= suiji if isresult { break } } // 构造游戏结算信息 dto := &GameSettleDto{ HitRate: hitRate, Suiji: suiji, IsResult: isresult, Rate: rate, } fishlogger.Infof("玩家:{%v}金币池为:{%v}炮倍:{%v}波动上限glp:{%v}鱼的ID为:{%v}=鱼的概率为:{%v}=suiji值获取:{%v}=hitRate值:{%v}=rate值:{%v},鱼id = {%v}", player.GetSnId(), player.MoneyPond, power, glp, fish.FishID, fishProb, dto.Suiji, dto.HitRate, dto.Rate, fish.TemplateID) return dto } func (data *FishingSceneData) checkIsmeet(fluctuateMaxMap map[string]float64, fishmu int32) string { glc := "" for key, value := range fluctuateMaxMap { if len(key) == 0 { continue } str := strings.Split(key, "-") start, _ := strconv.Atoi(str[0]) end, _ := strconv.Atoi(str[1]) if fishmu >= int32(start) && fishmu <= int32(end) { glc = strconv.FormatFloat(value, 'f', -1, 64) break } } if fishmu > 10000 { glc = strconv.FormatFloat(getMaxValue(fluctuateMaxMap), 'f', -1, 64) } return glc } func getMaxValue(fluctuateMaxMap map[string]float64) float64 { maxValue := math.Inf(-1) for _, value := range fluctuateMaxMap { if value > maxValue { maxValue = value } } return maxValue } /* event 对应得事件ID */ func (this *FishingSceneData) EventTreasureChestSettlements(power int32) (int32, []int32) { // 计算龙王多播相关得额外收益 var totalWeight int32 var eventCoin int32 for _, weight := range fishing.TreasureChestWeight { totalWeight = totalWeight + weight } NowWeight := rand.Int31n(totalWeight) var cumulativeWeight int32 for index, weight := range fishing.TreasureChestWeight { cumulativeWeight = cumulativeWeight + weight if NowWeight <= cumulativeWeight { treasureChestReward := fishing.TreasureChestReward[index] for _, value := range treasureChestReward { eventCoin = eventCoin + power*value } return eventCoin, treasureChestReward } } return 0, []int32{} } // fishSettlements 计算得分 // fishs 打死的鱼 // power 炮倍率 // event 事件 // ts 时间戳 // eventFishId 事件鱼标识 // eventFishCoin 事件鱼倍率 func (this *FishingSceneData) fishSettlements(fishs []*Fish, player *FishingPlayerData, power int32, event int32, ts int64, eventFishId int32, eventFishCoin int32) { var coin int64 // 鱼死亡本身得金币计算 var treasureChestReward []int32 pack := &fishing_proto.SCFireHit{ Snid: proto.Int32(player.SnId), Ts: proto.Int64(ts), EventFish: proto.Int32(eventFishId), EventCoin: proto.Int32(eventFishCoin * power), Power: proto.Int32(power), Event: proto.Int32(event), } var sumExp int32 = 0 for _, value := range fishs { var dropCoin int32 if value.Event == fishing.Event_Bit { dropCoin = 0 } else if value.Event == fishing.Event_TreasureChest { dropCoin, treasureChestReward = this.EventTreasureChestSettlements(power) fishlogger.Infof("Event_TreasureChest eventCoin %v treasureChestReward %v", dropCoin, treasureChestReward) } else if value.Event == fishing.Event_NewBoom { dropCoin = 0 } else if value.Event == fishing.Event_FreePower { dropCoin = 0 } else { dropCoin = value.DropCoin * power } //BOSS鱼死亡 更新BOSS池和个人池 if value.IsBoss == fishing.Boss { bossPond := base.GetCoinPoolMgr().GetBossPond(this.GetDBGameFree().SceneType) this.isBossDie(player, int64(dropCoin), bossPond) } pack.FishId = append(pack.FishId, value.FishID) pack.Coin = append(pack.Coin, dropCoin) key := player.MakeLogKey(value.TemplateID, power) if v, ok := player.logFishCount[key]; ok { v.Coin += dropCoin v.Num++ } else { player.logFishCount[key] = &model.FishCoinNum{ Coin: dropCoin, Num: 1, Power: power, } } fishlogger.Infof("logFishCount %v,%v,%v,%v", value.TemplateID, power, player.logFishCount[key].Coin, player.logFishCount[key].HitNum) coin = coin + int64(dropCoin) this.DelFish(value.FishID) value.SetDeath() //打死鱼增加玩家经验 sumExp += value.Exp } if event == fishing.Event_FreePower { player.UpdateFreePowerState() fishlogger.Infof("snid %v 更新为免费炮台", player.SnId) } if !this.GetTesting() && !player.IsRob { //5款捕鱼保持统一 player.NewStatics(0, coin) } player.winCoin += coin player.CoinCache += coin player.MoneyPond -= coin fishlogger.Infof("玩家:%v ,鱼死亡扣除金币池: %v ,当前金币池剩余:%v", player.SnId, coin, player.MoneyPond) fishlogger.Infof("fishSettlements player %v coin %v dropCoin %v , moneyPond = %v", player.SnId, player.CoinCache, coin, player.MoneyPond) pack.AddExp = sumExp oldLevel := player.Level player.AddPlayerExp(int64(sumExp)) if oldLevel != player.Level { //触发炮倍解锁事件 player.PlayerEvent(fishing.Event_Player_UpLevel, player.Level) } pack.CurrentPlayerCoin = proto.Int64(player.CoinCache) proto.SetDefaults(pack) this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_FIREHIT), pack, 0) // 连续开宝箱 if event == fishing.Event_TreasureChest { eventTreasureChestPack := &fishing_proto.SCTreasureChestEvent{ Snid: proto.Int32(player.SnId), Reward: treasureChestReward, CurrentPlayerCoin: proto.Int64(player.CoinCache), } proto.SetDefaults(eventTreasureChestPack) this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_TREASURECHESTEVENT), eventTreasureChestPack, 0) fishlogger.Infof("Event_TreasureChest BroadCastMessage %v", fishing_proto.FIPacketID_FISHING_SC_TREASURECHESTEVENT) } /* if !player.IsRob || model.GameParamData.IsRobFightTest { base.GetCoinPoolMgr().PopCoin(this.GetGameFreeId(), this.GetGroupId(), this.GetPlatform(), int64(coin)) } */ } func (this *FishingSceneData) PushBattle(player *FishingPlayerData, bulletid int32, fishs []int32, extfishis []int32) { bullet := player.bullet[bulletid] fishlogger.Infof("PushBattle player %v bullet %v fishs %v extfishis %v", player.SnId, bulletid, fishs, extfishis) if bullet == nil { fishlogger.Infof("%v not find in %v bullet buff. PushBattle player %v", bulletid, player.GetName(), player.SnId) return } battleData := &FishBattle{ SnId: bullet.SrcId, Bullet: bullet.Id, Power: bullet.Power, ExtFishis: extfishis, Multiple: bullet.Multiple, } if len(fishs) > 0 { battleData.FishsId = append(battleData.FishsId, int(fishs[0])) } select { case this.BattleBuff <- battleData: { delete(player.bullet, battleData.Bullet) } default: { delete(player.bullet, battleData.Bullet) fishlogger.Error("Player battle buff full.") } } } /* 向前端推送 绑定机器人对应的行为 behaviorCode 0 是 机器人 静默行为 */ func (this *FishingSceneData) SCRobotBehavior(snid, robotId int32, behaviorCode int32) { player := this.players[snid] if player == nil { fishlogger.Errorf("SCRobotBehavior player %v is empty,bullet will be droped.", snid) return } pack := &fishing_proto.SCRobotBehavior{ Code: proto.Int32(behaviorCode), RobotId: proto.Int32(robotId), } proto.SetDefaults(pack) player.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_SCROBOTBEHAVIOR), pack) } // PushBullet 开炮 // 玩家开炮,记录税收和消息广播 func (this *FishingSceneData) PushBullet(snid, x, y, id, power, fishId, multiple int32) fishing_proto.OpResultCode { player := this.players[snid] if player == nil { fishlogger.Errorf("player %v is empty,bullet will be droped.", snid) return fishing_proto.OpResultCode_OPRC_Error } if power <= 0 || power != player.power { fishlogger.Tracef("[%v %v] power is invalid(%v) currpower(%v).", player.GetName(), player.SnId, power, player.power) return fishing_proto.OpResultCode_OPRC_Error } //判断玩家发炮倍数 if multiple == 1 || multiple == 2 || multiple == 4 { if multiple == 4 { skillTemp := srvdata.PBDB_FishSkillMgr.GetData(103) if skillTemp == nil { return fishing_proto.OpResultCode_OPRC_Error } if player.VIP < skillTemp.Fury { fishlogger.Errorf("4倍炮弹,VIP等级不足 SnId = %v", player.SnId) return fishing_proto.OpResultCode_OPRC_Error } } } else { fishlogger.Errorf("炮弹倍数错误,SnId = %v,multiple = %v", player.SnId, multiple) return fishing_proto.OpResultCode_OPRC_Error } if (multiple == 2 || multiple == 4) && player.powerType != 0 { //狂暴下已经打死特属鱼了,再发狂暴子弹 直接return return fishing_proto.OpResultCode_OPRC_Error } // 检测当前玩家的的金币数够不够 if !player.CoinCheck(power * multiple) { fishlogger.Tracef("%v no enough coin to fishing.", player.GetName()) return fishing_proto.OpResultCode_OPRC_CoinNotEnough } curTime := time.Now().Unix() % BULLETLIMIT sbl := player.BulletLimit[curTime] // 子弹的数量限制,统一按最高倍速处理,配合10秒窗口期 bulletCountLimit := int64(12) // start 玩家的开火率 》 0 的时候 子弹的数量限制 设置为 10 //if player.FireRate > 0 { // bulletCountLimit = 10 //} // 判断子弹的数量 是否过大 if sbl > bulletCountLimit { //10秒的窗口期,避免堆包误判 total := sbl for i := 1; i < WINDOW_SIZE; i++ { total += player.BulletLimit[(int(curTime)-i+BULLETLIMIT)%BULLETLIMIT] } if total/WINDOW_SIZE > bulletCountLimit { fishlogger.Infof("Player bullet too fast.") //子弹打飞机了~~~ key := player.MakeLogKey(0, power) if v, ok := player.logFishCount[key]; ok { v.HitNum++ } else { player.logFishCount[key] = &model.FishCoinNum{ HitNum: 1, ID: 0, //飞机??? Power: power, } } return fishing_proto.OpResultCode_OPRC_Error } } else { player.BulletLimit[curTime] = sbl + 1 } player.bullet[id] = &Bullet{ Id: id, Power: power, SrcId: player.SnId, LifeTime: 0, Multiple: multiple, } if !this.GetTesting() && !player.IsRob { //5款捕鱼保持统一 player.NewStatics(int64(power*multiple), 0) } // start 对玩家身上的金币变化进行变更 if player.powerType != FreePowerType { // 只有当前炮台不是免费炮台的时候,才计算相关金额 player.LostCoin += int64(power * multiple) player.CoinCache -= int64(power * multiple) //fishlogger.Infof("player %v coin %v", player.SnId, player.CoinCache) player.SetTotalBet(player.GetTotalBet() + int64(power*multiple)) //if this.GetDBGameFree().GetGameId() != int32(common.GameId_NFishing) { //player.Statics(this.KeyGameId, this.KeyGamefreeId, -int64(power), true) player.LastRechargeWinCoin += int64(power * multiple) if _, ok := player.TodayGameData.CtrlData[this.GetKeyGameId()]; !ok { player.TodayGameData.CtrlData[this.GetKeyGameId()] = model.NewPlayerGameStatics() } player.TodayGameData.CtrlData[this.GetKeyGameId()].TotalIn += int64(power * multiple) // 添加每日写入数据 } else { player.FreePowerNum-- if player.FreePowerNum == 0 { player.UpdateNormalPowerState() // 状态变更 fishlogger.Infof("snid %v , 更新为普通炮台", player.SnId) } } //更新玩家最后发炮时间 player.LastFireTime = time.Now() // start 根据税收调整对应的比例 , 并且调整整个水池的逻辑 //if !player.IsRob { //增加个人金币池 //玩家发炮增加金币池数值 //var multiple int32 = 1 //当前默认的倍数只有一倍 后期增加了再改 var moneyScore = int64(float64(power) * float64(multiple) * float64(1.0-this.GetDraw()/1000)) //var moneyScore = int64(float64(power) * float64(1.0-this.GetDraw()/1000)) //普通跑增加个人金币池 其他状态的炮不增加 if moneyScore > 0 && player.powerType == 0 { player.MoneyPond += moneyScore } fishlogger.Infof("玩家发炮snid= %v, 当前玩家金币池:%v,本次增加的金币moneyScore = %v", player.SnId, player.MoneyPond, moneyScore) //公共池 //publicPond := int64(float64(power) * float64((this.GetPublicPondRatio()))) playerCount := len(this.Players) roomCount := 1 if math.Ceil(float64(playerCount/4)) != 0 { roomCount = int(math.Ceil(float64(playerCount / 4))) } fmt.Println("roomCount = ", roomCount) //增加公共奖池 暂时不要 //base.GetCoinPoolMgr().AddPublicPond(l(this.gameId), publicPond) pack := &fishing_proto.SCFire{ Snid: proto.Int32(player.SnId), X: proto.Int32(x), Y: proto.Int32(y), Bulletid: proto.Int32(id), Power: proto.Int32(power), CurrentPlayerCoin: proto.Int64(player.CoinCache), FishId: proto.Int32(fishId), Multiple: proto.Int32(multiple), } proto.SetDefaults(pack) this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_FIRE), pack, 0) //if player.GameData[this.GetKeyGameId()].GameTimes%15 == 0 { // curCoin := coinPoolMgr.GetCoin(this.GetGameFreeId(), this.GetPlatform(), this.GetGroupId()) // player.SaveFishingLog(curCoin, this.GetKeyGameId()) //} return fishing_proto.OpResultCode_OPRC_Sucess } // 同步屏幕存在的鱼 func (this *FishingSceneData) SyncFish(player *base.Player) { var cnt int var fishes []*fishing_proto.FishInfo syncFish := false pack := &fishing_proto.SCSyncFishCoin{} for _, fish := range this.fish_list { if fish.IsDeath(this.TimePoint) { continue } fishes = append(fishes, &fishing_proto.FishInfo{ FishID: fish.FishID, FishType: fish.FishType, FishPath: fish.Path, FishSpeed: fish.Speed, BirthTick: fish.BirthTick, LiveTick: fish.LiveTick, FishChild: fish.Child, }) cnt++ if fish.TemplateID == fishing.Fish_CaiShen { pack.FishId = proto.Int32(fish.FishID) pack.Coin = proto.Int64(int64(fish.DropCoin)) syncFish = true } } fishlogger.Trace("Current fish list count:", cnt) fishlogger.Trace("Current timePoint :", this.TimePoint) packFishes := &fishing_proto.SCFishesEnter{ //PolicyId: proto.Int32(this.PolicyId), Fishes: fishes, IceSec: proto.Int32(int32(0)), TimeTick: proto.Int32(this.TimePoint), } proto.SetDefaults(packFishes) player.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_FISHERENTER), packFishes) if syncFish { player.SendToClient(int(fishing_proto.FIPacketID_FISHING_SC_SCSYNCFISHCOIN), pack) } } // fishEvent 记录鱼触发的事件 func (this *FishingSceneData) fishEvent(fish *Fish, player *FishingPlayerData, power int32, ts int64, extfishs []int32) []*Fish { var deathFishs []*Fish if fish.Event == 0 { deathFishs = append(deathFishs, fish) return deathFishs } // 随机事件 if fish.Event == fishing.Event_Rand { fish.Event = common.RandInt32Slice([]int32{int32(fishing.Event_Booms), int32(fishing.Event_Boom), int32(fishing.Event_Ring)}) } // 普通事件 switch fish.Event { case fishing.Event_Ring: { //冰冻鱼事件 后续做 /* deathFishs = append(deathFishs, fish) for _, value := range this.fish_list { value.LiveTick += 100 if value.BirthTick >= this.TimePoint { value.BirthTick += 100 } } this.NextTime += time.Second.Nanoseconds() * 10 //冰冻鱼的冰冻时间 暂时设置为1秒 this.frozenTick = 1 pack := &fishing_proto.SCFreeze{SnId: proto.Int32(player.SnId), FishId: proto.Int32(fish.FishID)} this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_FREEZE), pack, 0)*/ } case fishing.Event_Booms, fishing.Event_Boom, fishing.Event_Lightning, fishing.Event_Same, fishing.Event_TreasureChest: { fishlogger.Tracef("Event fish %v-%v.", fish.TemplateID, fish.Event) fishlogger.Trace("Event ts:", ts) sign := fmt.Sprintf("%v;%v;%v;%v;", fish.Event, fish.FishID, ts, player.SnId) sign = common.MakeMd5String(sign) player.fishEvent[sign] = &FishingPlayerEvent{ FishId: fish.FishID, Event: fish.Event, Power: power, DropCoin: fish.DropCoin, Ts: ts, ExtFishId: extfishs, } fishlogger.Trace("Event sign:", sign) deathFishs = append(deathFishs, fish) } case fishing.Event_NewBoom, fishing.Event_Bit, fishing.Event_FreePower: { fishlogger.Tracef("Event fish %v-%v.", fish.TemplateID, fish.Event) fishlogger.Trace("Event ts:", ts) sign := fmt.Sprintf("%v;%v;%v;%v;", fish.Event, fish.FishID, ts, player.SnId) sign = common.MakeMd5String(sign) fishlogger.Infof("playerID %v ,sign %v , fishId %v , eventId %v", player.SnId, sign, fish.FishID, fish.Event) player.fishEvent[sign] = &FishingPlayerEvent{ FishId: fish.FishID, Event: fish.Event, Power: power, Ts: ts, ExtFishId: extfishs, } fishlogger.Trace("Event sign:", sign) deathFishs = append(deathFishs, fish) } default: //一网打尽(同组的鱼) { fishlogger.Trace("Event fish:", fish) eventFishs := this.fish_Event[fish.Event] fishlogger.Trace("eventFishs:", eventFishs) for _, fishId := range eventFishs { fishLink := this.fish_list[fishId] if fishLink == nil { fishlogger.Trace("Event link fish is null:", fishId) continue } if fishLink.IsDeath(this.TimePoint) { fishlogger.Tracef("Event link fish is death:%v-%v", fishLink.FishID, fishId) continue } if !fishLink.IsBirth(this.TimePoint) { fishlogger.Tracef("Event link fish is not birth:%v-%v", fishLink.FishID, fishId) continue } fishlogger.Trace("Event link fish:", fishLink) fishlogger.Trace("Drop coin:", fishLink.DropCoin*power) deathFishs = append(deathFishs, fishLink) } } } return deathFishs } // PushEventFish 客户端触发鱼事件 // sign 事件唯一标识 // fishs 事件关联的鱼标识 // eventFish 产生事件的鱼标识 func (this *FishingSceneData) PushEventFish(player *FishingPlayerData, sign string, fishs []int32, eventFish int32) bool { // 获取事件 fishEvent := player.fishEvent[sign] // 根据 Sign 确定触发鱼本身的事件 if fishEvent == nil { fishlogger.Error("Recive event fish sign error.") fishlogger.Trace("Event sign:", sign) return false } else { fishlogger.Infof("PushEventFish fishEvent %v, %v, sign %v", fishEvent.Event, fishEvent.Ts, sign) } // 接收 Fish 的 相关事件 太晚了 var timeout time.Duration if fishEvent.Event == fishing.Event_Bit { timeout = 15 } else { timeout = 10 } if fishEvent.Ts < time.Now().Add(-time.Second*timeout).Unix() { fishlogger.Error("Recive event fish list to late.") fishlogger.Infof("Event ts: %v", fishEvent.Ts) fishlogger.Infof("Event event:%v", fishEvent.Event) delete(player.fishEvent, sign) // 消费掉对应的sign return false } fishlogger.Infof("PushEventFish(client): %v", fishs) fishlogger.Infof("PushEventFish(srv): %v", fishEvent.ExtFishId) // selFishs 获取关联的所有鱼 var selFishs []*Fish // start 获取当前场景 中的 Fish 对象 for _, id := range fishEvent.ExtFishId { //用碰撞时带上来的id,防作弊 fish := this.fish_list[id] if fish == nil || fish.IsDeath(this.TimePoint) { continue } if fishEvent.Event == fishing.Event_Bit && (fish.FishType == 7 || fish.FishType == 8 || fish.FishType == 6) { fishlogger.Infof("钻头贝事件,屏蔽的鱼 %v", fish.TemplateID) continue } selFishs = append(selFishs, fish) } if fishEvent.Event == fishing.Event_Bit { for _, id := range fishs { //用碰撞时带上来的id,防作弊 fish := this.fish_list[id] if fish == nil || fish.IsDeath(this.TimePoint) { continue } if fish.FishType == 7 || fish.FishType == 8 || fish.FishType == 6 { fishlogger.Infof("钻头贝事件,屏蔽的鱼 %v", fish.TemplateID) continue } selFishs = append(selFishs, fish) } } // end if fishEvent.Event == fishing.Event_Bit { if len(fishs) == 0 { fishlogger.Errorf(" Event_Bit Event fish die all.") delete(player.fishEvent, sign) // 消费掉对应的sign this.fishSettlements(selFishs, player, fishEvent.Power, fishEvent.Event, time.Now().UnixNano(), eventFish, 0) return false } } else { if len(selFishs) == 0 { fishlogger.Errorf("Event fish die all.") delete(player.fishEvent, sign) // 消费掉对应的sign this.fishSettlements(selFishs, player, fishEvent.Power, fishEvent.Event, time.Now().UnixNano(), eventFish, fishEvent.DropCoin) return false } } if fishEvent.Event == fishing.Event_Bit && (len(selFishs) > 1) { delete(player.fishEvent, sign) // 消费掉对应的sign } else if fishEvent.Event != fishing.Event_Bit { delete(player.fishEvent, sign) // 消费掉对应的sign } // start 根据不同的场景截取 结算的 Fish if fishEvent.Event == fishing.Event_Boom && len(selFishs) > 15 { selFishs = selFishs[:15] } if fishEvent.Event == fishing.Event_Lightning && len(selFishs) > 35 { selFishs = selFishs[:35] } if fishEvent.Event == fishing.Event_Booms && len(selFishs) > 30 { selFishs = selFishs[:30] } if fishEvent.Event == fishing.Event_Same && len(selFishs) > 30 { selFishs = selFishs[:30] } // 新事件鱼代码处理相关 if fishEvent.Event == fishing.Event_Bit && len(selFishs) > 50 { selFishs = selFishs[:50] } if fishEvent.Event == fishing.Event_NewBoom && len(selFishs) > 50 { selFishs = selFishs[:50] } // end // 进行 鱼类结算 if fishEvent.Event == fishing.Event_Bit { if len(selFishs) == 1 { } else { this.fishSettlements(selFishs, player, fishEvent.Power, fishEvent.Event, time.Now().UnixNano(), eventFish, 0) } } else { this.fishSettlements(selFishs, player, fishEvent.Power, fishEvent.Event, time.Now().UnixNano(), eventFish, fishEvent.DropCoin) } return true } func (this *FishingSceneData) BroadCastMessage(packetid int, msg proto.Message, excludeSid int64) { mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion) for _, p := range this.players { if p == nil || p.GetGateSess() == nil { continue } if !p.IsOnLine() || p.IsMarkFlag(base.PlayerState_Leave) { continue } if p.GetSid() == excludeSid { continue } mgs[p.GetGateSess()] = append(mgs[p.GetGateSess()], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.GetSid()), }, }) } audiences := this.GetAudiences() for _, p := range audiences { if p == nil || p.GetGateSess() == nil { continue } if !p.IsOnLine() || p.IsMarkFlag(base.PlayerState_Leave) { continue } if p.GetSid() == excludeSid { continue } mgs[p.GetGateSess()] = append(mgs[p.GetGateSess()], &srvlibproto.MCSessionUnion{ Mccs: &srvlibproto.MCClientSession{ SId: proto.Int64(p.GetSid()), }, }) } for gateSess, v := range mgs { if gateSess == nil || len(v) == 0 { continue } action.MulticastMessageToServer(gateSess, packetid, msg, v...) } } func (this *FishingSceneData) syncFishCoin(fish *Fish) { pack := &fishing_proto.SCSyncFishCoin{ FishId: proto.Int32(fish.FishID), Coin: proto.Int64(int64(fish.DropCoin)), } proto.SetDefaults(pack) this.BroadCastMessage(int(fishing_proto.FIPacketID_FISHING_SC_SCSYNCFISHCOIN), pack, 0) } // GetDraw 获取金币池抽水百分比 func (this *FishingSceneData) GetDraw() float64 { draw := this.GetDBGameFree().GetDraw() return float64(draw / 100.0) } // GetBossDrainageBet 获取BOSS池抽水百分比 func (this *FishingSceneData) GetBossDrainageBet() float64 { bossDraw := this.GetDBGameFree().GetBossDrainageBet() return float64(bossDraw / 100.0) } // 获取公共池抽水百分比 func (this *FishingSceneData) GetPublicPondRatio() float64 { ratio := this.GetDBGameFree().GetRatio() return float64(ratio / 1000.0) } // 增加boss池 func (this *FishingSceneData) AddBossPond(player *FishingPlayerData, fishtype int32, bulletM int32) int64 { bossPond := int64(0) // boss抽水比例 bossRatio := this.GetBossDrainageBet() score := int64(float64(bulletM) * bossRatio) // 打食人鱼BOSS if fishtype == fishing.SUNWUKONG { //bossPond = publicPandService.AddPiranhaBossPond(TableConfig.GetInc().GetServiceId(), tableInfo.TableId, score) } else { fishlogger.Infof("玩家:%v, 鱼的ID为:%v, Boss抽水比例:%v, Boss池增加的数值:%v\n", player.SnId, fishtype, bossRatio, score) // 减掉个人池数值 if score > 0 { player.MoneyPond -= score base.GetCoinPoolMgr().AddBossPond(this.GetDBGameFree().SceneType, score) } } return bossPond } // Boss死亡 更新各种池 func (this *FishingSceneData) isBossDie(player *FishingPlayerData, score int64, bossPond int64) { minNum := score if minNum > bossPond { minNum = bossPond } player.MoneyPond += minNum base.GetCoinPoolMgr().AddBossPond(this.GetDBGameFree().SceneType, -minNum) fishlogger.Infof("玩家:%v,Boss奖池剩余金币数量:%v\n", player.SnId, bossPond) } // PathUsable 路径可用 func (this *FishingSceneData) PathUsable(path int32) bool { // 加锁管理 /* this.fishsMutex.Lock() defer this.fishsMutex.Unlock() // 当前时间 now := time.Now().Unix() // 遍历鱼 for _, v := range this.fish_list { if v.Path == path { //相同路径 比较出鱼时间 小于2秒 不让用 if now-v.InitTime <= 2 { return false } } }*/ return true } // 暂停出鱼 func (this *FishingSceneData) Freeze(sec int64) { this.af.Pause(sec * 1000) // 增加普通出鱼生命周期 offset := int32(sec * 1000 / 100) for _, f := range this.fish_list { f.AddTime(offset) } } // 停止出鱼 func (this *FishingSceneData) Stop() bool { //停止出鱼 this.af.Stop() return true }