game_sync/gamesrv/fishing/scenedata_fishing.go

1561 lines
49 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("玩家:%vBoss奖池剩余金币数量%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
}