package smallrocket

import (
	"mongo.games.com/game/model"
	"mongo.games.com/game/protocol/smallrocket"
	"time"

	"mongo.games.com/goserver/core"
	"mongo.games.com/goserver/core/logger"

	"mongo.games.com/game/common"
	rule "mongo.games.com/game/gamerule/smallrocket"
	"mongo.games.com/game/gamesrv/base"
	"mongo.games.com/game/proto"
)

var PolicySmallRocketSingleton = &PolicySmallRocket{}

type PolicySmallRocket struct {
	base.BaseScenePolicy
	states [rule.SmallRocketSceneStateMax]base.SceneState
}

func (this *PolicySmallRocket) CreateSceneExData(s *base.Scene) interface{} {
	sceneEx := NewSmallRocketSceneData(s)
	if sceneEx != nil {
		if sceneEx.init() {
			s.ExtraData = sceneEx
		}
	}
	return sceneEx
}

func (this *PolicySmallRocket) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} {
	playerEx := &PlayerEx{Player: p}
	if playerEx != nil {
		p.ExtraData = playerEx
	}
	return playerEx
}

func (this *PolicySmallRocket) OnStart(s *base.Scene) {
	logger.Logger.Trace("(this *PolicySmallRocket) OnStart, sceneId=", s.GetSceneId())

	sceneEx := NewSmallRocketSceneData(s)
	if sceneEx != nil {
		if sceneEx.init() {
			s.ExtraData = sceneEx
			s.ChangeSceneState(rule.SmallRocketSceneStateWait)
		}
	}
}

func (this *PolicySmallRocket) OnStop(s *base.Scene) {
	logger.Logger.Trace("(this *PolicyThirteen) OnStop , sceneId=", s.GetSceneId())
}

func (this *PolicySmallRocket) OnTick(s *base.Scene) {
	if s == nil {
		return
	}
	if s.SceneState != nil {
		s.SceneState.OnTick(s)
	}
}

func (this *PolicySmallRocket) OnPlayerEnter(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}

	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.SnId)

	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		pos := -1
		for i := 0; i < sceneEx.GetPlayerNum(); i++ {
			if sceneEx.seats[i] == nil {
				pos = i
				break
			}
		}
		if pos != -1 {
			playerEx := &PlayerEx{Player: p}
			sceneEx.seats[pos] = playerEx
			sceneEx.players[p.SnId] = playerEx

			baseScore := sceneEx.GetBaseScore()

			p.Pos = pos
			p.ExtraData = playerEx
			playerEx.Clear(baseScore)

			if sceneEx.Gaming {
				p.MarkFlag(base.PlayerState_WaitNext)
				p.UnmarkFlag(base.PlayerState_Ready)
			}

			//给自己发送房间信息
			this.SendRoomInfo(s, p, sceneEx)
			s.FirePlayerEvent(p, base.PlayerEventEnter, nil)
		}
	}
}

func (this *PolicySmallRocket) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) {
	logger.Logger.Trace("(this *PolicyThirteen) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if s == nil || p == nil {
		return
	}
	if !this.CanChangeCoinScene(s, p) {
		return
	}

	sceneEx, ok := s.ExtraData.(*SceneEx)
	if !ok {
		return
	}
	playerEx, ok := p.ExtraData.(*PlayerEx)
	if !ok {
		return
	}

	isBilled := false

	// 游戏已开始，玩家离开，备份玩家数据
	if sceneEx.Gaming {
		isBilled = playerEx.IsFinishTakeBet(sceneEx.GetSceneState().GetState())
		sceneEx.BackupPlayer(playerEx, isBilled)
	}

	// 清理玩家数据
	sceneEx.OnPlayerLeave(p, reason)
	s.FirePlayerEvent(p, base.PlayerEventLeave, nil)
}

func (this *PolicySmallRocket) OnPlayerDropLine(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.SnId)
	s.FirePlayerEvent(p, base.PlayerEventDropLine, nil)
}

func (this *PolicySmallRocket) OnPlayerRehold(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if _, ok := p.ExtraData.(*PlayerEx); ok {
			//发送房间信息给自己
			if p.IsGameing() {
				p.MarkFlag(base.PlayerState_Ready)
			}
			this.SendRoomInfo(s, p, sceneEx)
			s.FirePlayerEvent(p, base.PlayerEventRehold, nil)
		}
	}
}

func (this *PolicySmallRocket) OnPlayerReturn(s *base.Scene, p *base.Player) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if _, ok := p.ExtraData.(*PlayerEx); ok {
			//发送房间信息给自己
			if p.IsGameing() {
				p.MarkFlag(base.PlayerState_Ready)
			}
			this.SendRoomInfo(s, p, sceneEx)
			s.FirePlayerEvent(p, base.PlayerEventReturn, nil)
		}
	}
}

func (this *PolicySmallRocket) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if s == nil || p == nil {
		return false
	}
	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerOp, sceneId=", s.GetSceneId(), " player=", p.SnId, " opcode=", opcode, " params=", params)
	if s.SceneState != nil {
		p.LastOPTimer = time.Now()
		p.Trusteeship = 0
		return s.SceneState.OnPlayerOp(s, p, opcode, params)
	}
	return true
}

func (this *PolicySmallRocket) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	if s == nil || p == nil {
		return
	}
	logger.Logger.Trace("(this *PolicySmallRocket) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " eventcode=", evtcode, " params=", params)
	if s.SceneState != nil {
		s.SceneState.OnPlayerEvent(s, p, evtcode, params)
	}
}

func (this *PolicySmallRocket) IsCompleted(s *base.Scene) bool {
	if s == nil {
		return false
	}
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		return !sceneEx.Gaming
	}
	return false
}

func (this *PolicySmallRocket) IsCanForceStart(s *base.Scene) bool {
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		return len(s.Players) >= 2 && !sceneEx.Gaming
	}
	return false
}

func (this *PolicySmallRocket) ForceStart(s *base.Scene) {
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if sceneEx.SceneState.GetState() == rule.SmallRocketSceneStateWait {
			s.ChangeSceneState(rule.SmallRocketSceneStateStart)
		}
	}
}

// 当前状态能否退出游戏
func (this *PolicySmallRocket) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {
	if s == nil || p == nil {
		return false
	}
	if s.GetSceneState() != nil {
		return s.GetSceneState().CanChangeCoinScene(s, p)
	}

	return true
}

func (this *PolicySmallRocket) SendRoomInfo(s *base.Scene, p *base.Player, sceneEx *SceneEx) {
	pack := sceneEx.SamllRocketCreateRoomInfoPacket(s, p)
	p.SendToClient(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_ROOMINFO), pack)
}

// 广播房间状态  params[0]: bombMul  params[1]: bombRandomVal
func SmallRocketBroadcastRoomState(s *base.Scene, params ...float32) {
	pack := &smallrocket.SCSmallRocketRoomState{
		State:  proto.Int(s.SceneState.GetState()),
		Params: params,
	}
	s.Broadcast(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_ROOMSTATE), pack, 0)
}

// 广播下注人数
func SmallRocketBroadcastRoomBetPlayerNum(s *base.Scene, params ...int32) {
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		logger.Logger.Trace("SmallRocketBroadcastRoomBetPlayerNum, sceneId=", s.GetSceneId(), " | sceneEx.TotalBetPlayer=", sceneEx.TotalBetPlayer)

		if sceneEx.TotalBetPlayer < 0 {
			sceneEx.TotalBetPlayer = 0
		}

		pack := &smallrocket.SCSmallRocketBetPlayerChange{
			TotalBetPlayerCnt: proto.Int(sceneEx.TotalBetPlayer),
		}
		s.Broadcast(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_ROOMPLAYERBETNUM), pack, 0)
	}
}

// 广播有玩家领取收益跳伞
func SmallRocketBroadcastRoomPlayerTakeGain(s *base.Scene, snId int32, LeaveTime float64) {

	if _, ok := s.ExtraData.(*SceneEx); ok {
		pack := &smallrocket.SCSmallRocketPlayerTakeGain{
			SnId:      proto.Int32(snId),
			LeaveTime: proto.Float32(float32(LeaveTime)),
		}
		s.Broadcast(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_PLAYERTAKEGAIN), pack, 0)
	}
}

// 玩家信息变化
func SmallRocketSendPlayerInfo(s *base.Scene, p *PlayerEx, betDataInfo []*rule.BetDataEx, GainCoinBet1 int64, GainCoinBet2 int64) {

	if _, ok := s.ExtraData.(*SceneEx); ok {
		pack := &smallrocket.SCSmallRocketPlayerInfo{
			SnId:         proto.Int32(p.SnId),
			Coin:         proto.Int64(p.Coin),
			GainCoin:     proto.Int64(p.gainCoin),
			GainCoinBet1: GainCoinBet1,
			GainCoinBet2: GainCoinBet2,
		}

		if betDataInfo != nil {
			for i := 0; i < len(betDataInfo); i++ {

				tempBetEml := &smallrocket.BetDataInfo{
					BetVal:           proto.Int64(betDataInfo[i].BetVal),
					TakeMul:          proto.Float32(float32(betDataInfo[i].TakeMul)),
					IsCurBet:         proto.Bool(betDataInfo[i].IsCurBet),
					IsNextBet:        proto.Bool(betDataInfo[i].IsNextBet),
					IsTakeGain:       proto.Bool(betDataInfo[i].IsTakeGain),
					IsAutoBetAndTake: proto.Bool(betDataInfo[i].IsAutoBetAndTake),
				}

				pack.BetDataArr = append(pack.BetDataArr, tempBetEml)
			}
		}

		p.SendToClient(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_PLAYERINFO), pack)
	}
}

//=====================================
// BaseState 状态基类
//=====================================

type BaseState struct {
}

func (this *BaseState) GetTimeout(s *base.Scene) int {
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		return int(time.Now().Sub(sceneEx.StateStartTime) / time.Second)
	}
	return 0
}

func (this *BaseState) CanChangeTo(s base.SceneState) bool {
	return true
}

func (this *BaseState) CanChangeCoinScene(s *base.Scene, p *base.Player) bool {

	//playerEx, ok := p.ExtraData.(*PlayerEx)
	//if !ok {
	//	return false
	//}
	//
	//if !playerEx.CanLeaveScene(s.GetSceneState().GetState()) {
	//	return false
	//}

	return true
}

func (this *BaseState) OnEnter(s *base.Scene) {
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		sceneEx.StateStartTime = time.Now()
	}
}

func (this *BaseState) OnLeave(s *base.Scene) {}

func (this *BaseState) OnTick(s *base.Scene) {
}

func (this *BaseState) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {

	sceneEx, ok := s.ExtraData.(*SceneEx)
	if !ok {
		return false
	}
	playerEx, ok := p.ExtraData.(*PlayerEx)
	if !ok {
		return false
	}

	switch opcode {
	case rule.SmallRocketPlayerOpSResumeGetPlayerInfo: //
		if len(params) >= 1 {

			params = append(params, playerEx.Coin)
			params = append(params, int64(this.GetTimeout(s)))
			sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)
		}
	}
	return false
}

func (this *BaseState) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
}

//=====================================
// StateWait 等待中
//=====================================

type StateWait struct {
	BaseState
}

func (this *StateWait) GetState() int {
	return rule.SmallRocketSceneStateWait
}

func (this *StateWait) CanChangeTo(s base.SceneState) bool {
	if s.GetState() == rule.SmallRocketSceneStateStart {
		return true
	}
	return false
}

func (this *StateWait) GetTimeout(s *base.Scene) int {

	return this.BaseState.GetTimeout(s)
}

func (this *StateWait) OnEnter(s *base.Scene) {
	this.BaseState.OnEnter(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if s.Gaming {
			s.NotifySceneRoundPause()
		}
		s.Gaming = false

		sceneEx.logic.LoadCrashSearchData()

		SmallRocketBroadcastRoomState(s, float32(0), float32(0))

		if sceneEx.CanStart() {
			s.ChangeSceneState(rule.SmallRocketSceneStateStart)
		}
	}
}

// 玩家事件
func (this *StateWait) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	logger.Logger.Trace("(this *StateWait) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode)
	this.BaseState.OnPlayerEvent(s, p, evtcode, params)
	if _, ok := s.ExtraData.(*SceneEx); ok {
		switch evtcode {
		case base.PlayerEventLeave:
		case base.PlayerEventEnter:
			if !p.IsReady() {
				p.MarkFlag(base.PlayerState_Ready)
				p.SyncFlag()
			}
		}
	}
}

func (this *StateWait) OnTick(s *base.Scene) {
	this.BaseState.OnTick(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if s.CheckNeedDestroy() {
			sceneEx.SceneDestroy(true)
			return
		}
		if time.Now().Sub(sceneEx.StateStartTime) > rule.SmallRocketSceneWaitTimeout {
			//切换到准备开局状态
			if sceneEx.CanStart() {
				s.ChangeSceneState(rule.SmallRocketSceneStateStart)
			}
		}
	}
}

//=====================================
// StateStart 开始倒计时
//=====================================

type StateStart struct {
	BaseState
}

func (this *StateStart) GetState() int {
	return rule.SmallRocketSceneStateStart
}

func (this *StateStart) CanChangeTo(s base.SceneState) bool {
	switch s.GetState() {
	case rule.SmallRocketSceneStatePlayGame:
		return true
	}
	return false
}

func (this *StateStart) OnEnter(s *base.Scene) {
	this.BaseState.OnEnter(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		SmallRocketBroadcastRoomState(s, float32(0), float32(0))
		s.Gaming = false
		sceneEx.GameNowTime = time.Now()
		sceneEx.NumOfGames++

		sceneEx.TotalBetPlayer = 0
		sceneEx.BoomMul, sceneEx.BombRandomNum = sceneEx.logic.CalBoomMul(int(rule.SmallRocketBombRandomMulMaxE))

		sceneEx.logid, _ = model.AutoIncGameLogId()

		if sceneEx.BoomMul >= rule.SmallRocketBombRoomMulMaxE {
			sceneEx.BoomMul = rule.SmallRocketBombRoomMulMaxE
		}

		BoomTime := sceneEx.logic.GetBombTimeByBombMul(int32(sceneEx.BoomMul * rule.SmallRocketPlayerTransDataMul))
		if BoomTime < rule.SmallRocketPlayerTransDataMul {
			BoomTime = rule.SmallRocketPlayerTransDataMul
		}

		sceneEx.bombTime = time.Duration(float64(BoomTime) * float64(time.Second) / rule.SmallRocketPlayerTransDataMul)

		logger.Logger.Trace("StateStart------OnEnter: sceneEx.BombRandomNum: ", sceneEx.BombRandomNum, " | sceneEx.BoomMul: ", sceneEx.BoomMul, " | sceneEx.bombTime: ", sceneEx.bombTime)

		for _, playerEx := range sceneEx.players {
			if playerEx != nil {

				playerEx.PlayerAutoBet(this.GetState())

				playerEx.StopBetCoin()

				SmallRocketSendPlayerInfo(s, playerEx, playerEx.betData, 0, 0)

				for i := 0; i < len(playerEx.betData); i++ {
					if playerEx.betData[i].IsCurBet && !playerEx.betData[i].IsTakeGain {
						var gainSearchTime = float64(sceneEx.logic.GetBombTimeByBombMul(int32(playerEx.betData[i].TakeMul * float64(rule.SmallRocketPlayerTransDataMul))))
						if gainSearchTime < rule.SmallRocketPlayerTransDataMul {
							gainSearchTime = rule.SmallRocketPlayerTransDataMul
						}

						playerEx.betData[i].GainSearchTime = time.Duration((gainSearchTime / rule.SmallRocketPlayerTransDataMul) * float64(time.Second))
						logger.Logger.Trace("StateStart------OnEnter: SnId=", playerEx.SnId, " | betData[", i, "]: ", " | GainSearchTime: ", playerEx.betData[i].GainSearchTime)

						// 没有自动的才扣钱
						if !playerEx.IsAutoBetAndTakeByPos(int64(i)) {
							if playerEx.betData[i].BetVal > 0 {
								playerEx.AddCoin(-playerEx.betData[i].BetVal, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
							} else if playerEx.betData[i].BetVal < 0 {
								logger.Logger.Error("(this *StateStart) OnEnter, sceneid:", s.GetSceneId(), " | Player SnId:", playerEx.SnId, " | BetCoinVal:", playerEx.betData[i].BetVal)
								playerEx.PrintBetData(rule.SmallRocketSceneStateStart)
							}
						}
					}
				}

				playerEx.CopyToCurBetData()

				if sceneEx.logic.IsCurRoundBet(playerEx.betData) {
					playerEx.PrintBetData(rule.SmallRocketSceneStateStart)
					sceneEx.TotalBetPlayer++
				}
			}
		}

		SmallRocketBroadcastRoomBetPlayerNum(s)
	}
}

func (this *StateStart) OnTick(s *base.Scene) {
	this.BaseState.OnTick(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if time.Now().Sub(sceneEx.StateStartTime) > rule.SmallRocketSceneStartTimeout {
			//切换到等待操作状态
			if sceneEx.CanStart() {
				logger.Logger.Trace("StateStart------SmallRocketSceneStartTimeout: ", rule.SmallRocketSceneStartTimeout)
				s.ChangeSceneState(rule.SmallRocketSceneStatePlayGame)
			} else {
				s.ChangeSceneState(rule.SmallRocketSceneStateWait)
			}
		}
	}
}

func (this *StateStart) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	if this.BaseState.OnPlayerOp(s, p, opcode, params) {
		return true
	}

	sceneEx, ok := s.ExtraData.(*SceneEx)
	if !ok {
		return false
	}
	playerEx, ok := p.ExtraData.(*PlayerEx)
	if !ok {
		return false
	}

	//if !playerEx.IsGameing() {
	//	//returnFunc(thirteen.OpResultCode_OPRC_Error)
	//	return true
	//}

	logger.Logger.Trace("StateStart OnPlayerOp-----SnId:", playerEx.SnId, " opcode: ", opcode, " params:", params)
	playerEx.PrintBetData(rule.SmallRocketSceneStateStart)

	switch opcode {
	case rule.SmallRocketPlayerOpBet: // 下注
		if len(params) >= 3 {
			betPos := params[0]
			betVal := params[1]
			takeMul := params[2]

			if !sceneEx.CheckBetOp(betVal, takeMul) {
				return false
			}

			if len(playerEx.betData) >= 2 && (betPos >= 0 && betPos <= 1) {

				// 当前位置已经下注不允许再次下注
				if sceneEx.logic.IsCurRoundBetPos(playerEx.betData, betPos) && !playerEx.betData[betPos].IsAutoBetAndTake {
					sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_PosAlReadyBet, params, playerEx.betData)
					return false
				}

				// 检测能否下注
				if !playerEx.CanBetCoinByPos(int(betPos), betVal) {
					return false
				}

				// 之前没有下过注 下注人数增加, 通知服务器
				if !sceneEx.logic.IsCurRoundBet(playerEx.betData) {
					sceneEx.TotalBetPlayer++
					SmallRocketBroadcastRoomBetPlayerNum(s)
				}

				playerEx.betData[betPos].BetVal = betVal
				playerEx.betData[betPos].TakeMul = float64(takeMul) / 100.00
				playerEx.betData[betPos].IsCurBet = true
				playerEx.betData[betPos].IsNextBet = false
				playerEx.betData[betPos].IsTakeGain = false

				if playerEx.betData[betPos].IsCurBet {
					var gainSearchTime = float64(sceneEx.logic.GetBombTimeByBombMul(int32(playerEx.betData[betPos].TakeMul * float64(rule.SmallRocketPlayerTransDataMul))))
					if gainSearchTime < rule.SmallRocketPlayerTransDataMul {
						gainSearchTime = rule.SmallRocketPlayerTransDataMul
					}

					playerEx.betData[betPos].GainSearchTime = time.Duration((gainSearchTime / rule.SmallRocketPlayerTransDataMul) * float64(time.Second))

					if playerEx.betData[betPos].BetVal > 0 {
						playerEx.AddCoin(-playerEx.betData[betPos].BetVal, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
					} else if playerEx.betData[betPos].BetVal < 0 {
						logger.Logger.Error("(this *StateStart) OnPlayerOp, sceneid:", s.GetSceneId(), " | Player SnId:", playerEx.SnId, " | betData[", betPos, "]: ", " | BetCoinVal:", playerEx.betData[betPos].BetVal)
						playerEx.PrintBetData(rule.SmallRocketSceneStateStart)
					}

					logger.Logger.Trace("StateStart SmallRocketPlayerOpBet------SnId:", playerEx.SnId, " | betData[", betPos, "]: ", " | BetVal: ", playerEx.betData[betPos].BetVal)
				}

				params = append(params, playerEx.Coin)

				playerEx.CopyToCurBetData()

				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)
			}
		}
	case rule.SmallRocketPlayerOpSetAutoBet, rule.SmallRocketPlayerOpSetAutoTakeGain: // 设置自动下注状态
		if len(params) >= 4 {
			isAutoTakeGain := params[0]
			betPos := params[1]
			betVal := params[2]
			takeMul := params[3]

			if !sceneEx.CheckBetOp(betVal, takeMul) {
				return false
			}

			if len(playerEx.betData) >= 2 && (betPos >= 0 && betPos <= 1) {

				// 检测能否下注
				if !playerEx.CanBetCoinByPos(int(betPos), betVal) {
					return false
				}

				// 下一局已下注
				if playerEx.betData[betPos].IsNextBet {
					return false
				}

				// 本局还在下注状态下
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {
					return false
				}

				playerEx.betData[betPos].BetVal = betVal
				playerEx.betData[betPos].TakeMul = float64(takeMul) / 100.00
				playerEx.betData[betPos].IsCurBet = true

				playerEx.SetAutoBetAndTake(isAutoTakeGain, betPos)

				// 自动 下注未领取奖励
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {
					var gainSearchTime = float64(sceneEx.logic.GetBombTimeByBombMul(int32(playerEx.betData[betPos].TakeMul * float64(rule.SmallRocketPlayerTransDataMul))))
					if gainSearchTime < rule.SmallRocketPlayerTransDataMul {
						gainSearchTime = rule.SmallRocketPlayerTransDataMul
					}

					playerEx.betData[betPos].GainSearchTime = time.Duration((gainSearchTime / rule.SmallRocketPlayerTransDataMul) * float64(time.Second))

					if playerEx.betData[betPos].BetVal > 0 {
						playerEx.AddCoin(-playerEx.betData[betPos].BetVal, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
					} else if playerEx.betData[betPos].BetVal < 0 {
						logger.Logger.Error("(this *StateStart) OnPlayerOp 4 , sceneid:", s.GetSceneId(), " | Player SnId:", playerEx.SnId, " | BetCoinVal:", playerEx.betData[betPos].BetVal)
						playerEx.PrintBetData(rule.SmallRocketSceneStateStart)
					}
				}

				params = append(params, playerEx.Coin)

				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)

				playerEx.CopyToCurBetData()
			} else {
				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Error, params, playerEx.betData)
			}

		}
	case rule.SmallRocketPlayerOpAutoSubCoin:
		if len(params) >= 8 {
			//isAutoTakeGain := params[0]
			betPos0 := params[1]
			betVal0 := params[2]
			takeMul0 := params[3]

			betPos1 := params[5]
			betVal1 := params[6]
			takeMul1 := params[7]

			if !sceneEx.CheckBetOp(betVal0, takeMul0) {
				return false
			}

			if !sceneEx.CheckBetOp(betVal1, takeMul1) {
				return false
			}

			if len(playerEx.betData) >= 2 && (betPos0 >= 0 && betPos0 <= 1) && (betPos1 >= 0 && betPos1 <= 1) {

				playerEx.betData[betPos0].BetVal = betVal0
				playerEx.betData[betPos0].TakeMul = float64(takeMul0) / 100.00

				playerEx.betData[betPos1].BetVal = betVal1
				playerEx.betData[betPos1].TakeMul = float64(takeMul1) / 100.00

				playerEx.StopBetCoin()

				for i := 0; i < len(playerEx.betData); i++ {
					// 自动下注领取 扣除金币
					if playerEx.betData[i].IsCurBet && playerEx.betData[i].IsAutoBetAndTake {
						var gainSearchTime = float64(sceneEx.logic.GetBombTimeByBombMul(int32(playerEx.betData[i].TakeMul * float64(rule.SmallRocketPlayerTransDataMul))))
						if gainSearchTime < rule.SmallRocketPlayerTransDataMul {
							gainSearchTime = rule.SmallRocketPlayerTransDataMul
						}

						playerEx.betData[i].GainSearchTime = time.Duration((gainSearchTime / rule.SmallRocketPlayerTransDataMul) * float64(time.Second))

						if playerEx.betData[i].BetVal > 0 {
							playerEx.AddCoin(-playerEx.betData[i].BetVal, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
						} else if playerEx.betData[i].BetVal <= 0 {
							logger.Logger.Error("(this *StateStart) OnPlayerOp 7, sceneid:", s.GetSceneId(), " | Player SnId:", playerEx.SnId, " | BetCoinVal:", playerEx.betData[i].BetVal)
							playerEx.PrintBetData(rule.SmallRocketSceneStateStart)
						}

						//params = append(params, playerEx.Coin)
						//
						//sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)
					}
				}

				playerEx.CopyToCurBetData()
			} else {
				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Error, params, playerEx.betData)
			}
		}
	default:
		return false
	}
	return false
}

func (this *StateStart) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) {
	logger.Logger.Trace("(this *StateStart) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode)
	this.BaseState.OnPlayerEvent(s, p, evtcode, params)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		switch evtcode {
		case base.PlayerEventLeave:
			if !sceneEx.CanStart() {
				logger.Logger.Trace("(this *StateStart) OnPlayerEvent s.ChangeSceneState(SmallRocketSceneStateWait):", s.GetSceneId())
				s.ChangeSceneState(rule.SmallRocketSceneStateWait)
			}
		case base.PlayerEventEnter:
			if !p.IsReady() {
				p.MarkFlag(base.PlayerState_Ready)
				p.SyncFlag()
			}
		}
	}
}

// =====================================
// PlayGame 游戏中
// =====================================
type PlayGame struct {
	BaseState
}

func (this *PlayGame) GetState() int {
	return rule.SmallRocketSceneStatePlayGame
}

func (this *PlayGame) CanChangeTo(s base.SceneState) bool {
	switch s.GetState() {
	case rule.SmallRocketSceneStateBilled:
		return true
	}
	return false
}

func (this *PlayGame) OnEnter(s *base.Scene) {
	logger.Logger.Trace("(this *PlayGame) OnEnter, sceneid=", s.GetSceneId())

	this.BaseState.OnEnter(s)

	s.Gaming = true

	sceneEx, ok := s.ExtraData.(*SceneEx)
	if !ok {
		return
	}

	for _, playerEx := range sceneEx.players {
		if playerEx != nil {
			SmallRocketSendPlayerInfo(s, playerEx, playerEx.betData, 0, 0)
		}
	}

	SmallRocketBroadcastRoomState(s, float32(0), float32(0))
	SmallRocketBroadcastRoomBetPlayerNum(s)
}

func (this *PlayGame) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {

	logger.Logger.Trace("StatePlayGame OnPlayerOp-----SnId:", p.SnId, " opcode: ", opcode, " params:", params)

	if this.BaseState.OnPlayerOp(s, p, opcode, params) {
		return true
	}

	sceneEx, ok := s.ExtraData.(*SceneEx)
	if !ok {
		return false
	}
	playerEx, ok := p.ExtraData.(*PlayerEx)
	if !ok {
		return false
	}

	//if !playerEx.IsGameing() {
	//	//returnFunc(thirteen.OpResultCode_OPRC_Error)
	//	return true
	//}

	// playerEx.PrintBetData(rule.SmallRocketSceneStatePlayGame)

	switch opcode {
	case rule.SmallRocketPlayerOpBet: // 为下一局下注
		if len(params) >= 3 {
			betPos := params[0]
			betVal := params[1]
			takeMul := params[2]

			if !sceneEx.CheckBetOp(betVal, takeMul) {
				return false
			}

			if len(playerEx.betData) >= 2 && (betPos >= 0 && betPos <= 1) {

				// 检测能否下注
				if !playerEx.CanBetCoinByPos(int(betPos), betVal) {
					return false
				}

				// 下一局已下注
				if playerEx.betData[betPos].IsNextBet {
					return false
				}

				// 本局还在下注状态下
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {
					return false
				}

				playerEx.betData[betPos].BetVal = betVal
				playerEx.betData[betPos].TakeMul = float64(takeMul) / 100.00
				playerEx.betData[betPos].IsNextBet = true

				params = append(params, playerEx.Coin)

				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)
			}
		}
	case rule.SmallRocketPlayerOpCancelBet: //取消下一局下注
		if len(params) >= 1 {
			betPos := params[0]
			if len(playerEx.betData) >= 2 && betPos <= 1 {

				// 没有下注
				if !playerEx.betData[betPos].IsNextBet {
					return false
				}

				// 本局还在下注状态下
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {
					return false
				}

				playerEx.betData[betPos].IsNextBet = false

				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)
			}
		}

	case rule.SmallRocketPlayerOpTakeReward: // 下车收取奖励
		if len(params) >= 1 {
			betPos := params[0]

			if len(playerEx.betData) >= 2 && (betPos >= 0 && betPos <= 1) {
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {

					//var startTimeDur = time.Now().Sub(sceneEx.StateStartTime)
					//logger.Logger.Trace("StatePlayGame OnPlayerOp OpTakeReward:-----SnId:", playerEx.SnId, " startTimeDur: ", startTimeDur, " GainSearchTime:", playerEx.betData[betPos].GainSearchTime)

					gainSearchMul := sceneEx.logic.GetBombMulByBombTime(int32(this.GetTimeout(s) * rule.SmallRocketPlayerTransDataMul))

					gainCoinMul := float64(gainSearchMul) / rule.SmallRocketPlayerTransDataMul
					gainCoin := int64(float64(playerEx.betData[betPos].BetVal) * gainCoinMul)
					playerEx.gainCoin += gainCoin

					if gainCoin > 0 {
						playerEx.AddCoin(gainCoin, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
						playerEx.CurIsWin = 1
						playerEx.betData[betPos].GainCoinMul = gainCoinMul
					}

					playerEx.betData[betPos].IsTakeGain = true

					params = append(params, gainCoin)
					params = append(params, playerEx.Coin)

					sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)

					SmallRocketBroadcastRoomPlayerTakeGain(s, playerEx.SnId, float64(this.GetTimeout(s)))

					if sceneEx.logic.IsExistRoundTakenGain(playerEx.betData) {
						sceneEx.SubBetPlayerNum()
						SmallRocketBroadcastRoomBetPlayerNum(s)
					}

					playerEx.CopyToCurBetData()
				} else {
					sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Error, params, playerEx.betData)
				}
			}

		}
	case rule.SmallRocketPlayerOpSetAutoBet, rule.SmallRocketPlayerOpSetAutoTakeGain: // 设置自动下注状态
		if len(params) >= 4 {
			isAutoTakeGain := params[0]
			betPos := params[1]
			betVal := params[2]
			takeMul := params[3]

			if !sceneEx.CheckBetOp(betVal, takeMul) {
				return false
			}

			if len(playerEx.betData) >= 2 && (betPos >= 0 && betPos <= 1) {

				// 检测能否下注
				if !playerEx.CanBetCoinByPos(int(betPos), betVal) {
					return false
				}

				// 下一局已下注
				if playerEx.betData[betPos].IsNextBet {
					return false
				}

				// 本局还在下注状态下
				if playerEx.betData[betPos].IsCurBet && !playerEx.betData[betPos].IsTakeGain {
					return false
				}

				playerEx.betData[betPos].BetVal = betVal
				playerEx.betData[betPos].TakeMul = float64(takeMul) / 100.00

				playerEx.SetAutoBetAndTake(isAutoTakeGain, betPos)

				params = append(params, playerEx.Coin)
				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Success, params, playerEx.betData)

			} else {
				sceneEx.OnPlayerSCOp(p, opcode, smallrocket.OpResultCode_OPRC_Error, params, playerEx.betData)
			}

		}
	default:
		return false
	}
	return false
}

func (this *PlayGame) OnTick(s *base.Scene) {
	this.BaseState.OnTick(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {

		if time.Now().Sub(sceneEx.StateStartTime) > sceneEx.bombTime {
			logger.Logger.Trace("PlayGame------sceneEx.bombTime: ", sceneEx.bombTime)
			s.ChangeSceneState(rule.SmallRocketSceneStateBilled)
		} else {
			// 玩家自动收取功能
			for _, playerEx := range sceneEx.players {
				if playerEx != nil && playerEx.IsAutoBetAndTake() {
					for i := 0; i < len(playerEx.betData); i++ {
						if playerEx.betData[i].IsAutoBetAndTake && playerEx.betData[i].IsCurBet && !playerEx.betData[i].IsTakeGain {

							if time.Now().Sub(sceneEx.StateStartTime) >= playerEx.betData[i].GainSearchTime {

								gainCoin := int64(float64(playerEx.betData[i].BetVal) * playerEx.betData[i].TakeMul)
								playerEx.gainCoin += gainCoin
								logger.Logger.Trace("(this *PlayGame) OnTick: SnId:", playerEx.SnId, " | timeOut: ", time.Now().Sub(sceneEx.StateStartTime), " gainSearchTime: ", playerEx.betData[i].GainSearchTime)

								if gainCoin > 0 {
									playerEx.AddCoin(gainCoin, common.GainWay_SmallRocket, base.SyncFlag_ToClient, "system", s.GetSceneName())
									playerEx.CurIsWin = 1

									playerEx.betData[i].GainCoinMul = playerEx.betData[i].TakeMul

									if playerEx.betData[i].IsCurBet {
										playerEx.betData[i].IsTakeGain = true
									}

									logger.Logger.Trace("(this *PlayGame) OnTick------SnId:", playerEx.SnId, " | playerEx.gainCoin: ", gainCoin)

									GainCoinBet1 := int64(0)
									GainCoinBet2 := int64(0)
									if i == 0 {
										GainCoinBet1 = gainCoin
										GainCoinBet2 = 0
									} else if i == 1 {
										GainCoinBet1 = 0
										GainCoinBet2 = gainCoin
									}

									SmallRocketSendPlayerInfo(s, playerEx, playerEx.betData, GainCoinBet1, GainCoinBet2)

									//playerEx.PrintBetData(rule.SmallRocketSceneStatePlayGame)

									SmallRocketBroadcastRoomPlayerTakeGain(s, playerEx.SnId, float64(this.GetTimeout(s)))

									if sceneEx.logic.IsExistRoundTakenGain(playerEx.betData) {
										//sceneEx.TotalBetPlayer--
										sceneEx.SubBetPlayerNum()
										SmallRocketBroadcastRoomBetPlayerNum(s)
									}
								}
							}

						}
					}

					playerEx.CopyToCurBetData()
				}
			}
		}
	}
}

//=====================================
// StateBilled 结算
//=====================================

type StateBilled struct {
	BaseState
}

func (this *StateBilled) GetState() int {
	return rule.SmallRocketSceneStateBilled
}

func (this *StateBilled) CanChangeTo(s base.SceneState) bool {
	switch s.GetState() {
	case rule.SmallRocketSceneStateStart:
		return true
	}
	return false
}

func (this *StateBilled) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool {
	return false
}

func (this *StateBilled) OnEnter(s *base.Scene) {
	logger.Logger.Trace("(this *StateBilled) OnEnter, sceneid=", s.GetSceneId())
	this.BaseState.OnEnter(s)

	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {

		boomMul := sceneEx.BoomMul
		if boomMul < 1 {
			boomMul = 1
		}

		// 添加历史爆炸倍数记录
		sceneEx.HistoryBombMul.Push(boomMul)

		SmallRocketBroadcastRoomState(s, float32(0), float32(0))

		// 没离开，剩余玩家结算
		for _, playerEx := range sceneEx.players {
			if playerEx != nil {
				pack := &smallrocket.SCSmallRocketRoundGameBilled{
					RoundId: proto.Int32(int32(sceneEx.RoundId)),
					BombMul: proto.Float32(float32(boomMul)),
					Award:   proto.Int64(playerEx.gainCoin),
					Balance: proto.Int64(playerEx.Coin),
				}

				if sceneEx.HistoryBombMul != nil {
					hisBoomMul := sceneEx.HistoryBombMul.GetFloat64Items()
					for i := 0; i < len(hisBoomMul); i++ {
						pack.RoundBoomMuHistory = append(pack.RoundBoomMuHistory, float32(hisBoomMul[i]))
					}
				}

				// logger.Logger.Trace("SCSmallRocketRoundGameBilled is pack: ", pack)
				proto.SetDefaults(pack)

				playerEx.SendToClient(int(smallrocket.SmallRocketPacketID_PACKET_SC_SMALLROCKET_GAMEBILLED), pack)

				// 本局下注才记录
				if sceneEx.logic.IsCurRoundBet(playerEx.CurBetData) {
					sceneEx.Statistics(&base.StaticParam{
						SnId:           playerEx.SnId,
						Gain:           playerEx.gainCoin,
						GainTax:        playerEx.taxCoin,
						IsAddTimes:     true,
						HasRobotGaming: sceneEx.robotNum > 0,
					})

					logger.Logger.Trace("SmallRocketSaveLog Save ", playerEx.SnId)

					TotalBetValue := sceneEx.logic.GetRoundBetCoin(playerEx.CurBetData)

					// 统计金币变动
					changeCoin := playerEx.gainCoin - playerEx.taxCoin - int64(TotalBetValue)
					startCoin := playerEx.Coin - changeCoin

					playerEx.SaveSceneCoinLog(startCoin, changeCoin, playerEx.GetCoin(), int64(TotalBetValue), playerEx.taxCoin, playerEx.gainCoin, 0, 0)

					//GainTotalBetVal := sceneEx.logic.GetRoundGainCoin(playerEx.betData, )
					LogBaseResult := model.SmallRocketBaseResultType{}
					LogBaseResult.RoomId = int32(sceneEx.GetSceneId())
					LogBaseResult.TotalBetVal = int64(TotalBetValue)
					LogBaseResult.BeforeCoin = startCoin
					LogBaseResult.AfterCoin = playerEx.GetCoin()
					LogBaseResult.WinCoin = playerEx.gainCoin
					LogBaseResult.PlayerSnid = playerEx.SnId

					if len(playerEx.CurBetData) >= 2 {
						LogBaseResult.BetCoin1 = playerEx.CurBetData[0].BetVal
						LogBaseResult.BetMul1 = playerEx.CurBetData[0].TakeMul
						LogBaseResult.IsAutoBetAndTake1 = playerEx.CurBetData[0].IsAutoBetAndTake
						LogBaseResult.TakeBetMul1 = playerEx.CurBetData[0].GainCoinMul

						LogBaseResult.BetCoin2 = playerEx.CurBetData[1].BetVal
						LogBaseResult.BetMul2 = playerEx.CurBetData[1].TakeMul
						LogBaseResult.IsAutoBetAndTake2 = playerEx.CurBetData[1].IsAutoBetAndTake
						LogBaseResult.TakeBetMul2 = playerEx.CurBetData[1].GainCoinMul
					}

					if !playerEx.IsRob {
						info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult)
						if err == nil {
							sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{})
						}

						totalin := int64(TotalBetValue)
						totalout := playerEx.gainCoin
						validFlow := totalin + totalout
						validBet := common.AbsI64(totalin - totalout)
						logParam := &base.SaveGamePlayerListLogParam{
							Platform:          playerEx.Platform,
							Channel:           playerEx.Channel,
							Promoter:          playerEx.BeUnderAgentCode,
							PackageTag:        playerEx.PackageID,
							InviterId:         playerEx.InviterId,
							LogId:             sceneEx.logid,
							TotalIn:           totalin,
							TotalOut:          totalout,
							TaxCoin:           playerEx.taxCoin,
							BetAmount:         int64(TotalBetValue),
							WinAmountNoAnyTax: playerEx.gainCoin,
							ValidBet:          validBet,
							ValidFlow:         validFlow,
							IsFirstGame:       sceneEx.IsPlayerFirst(playerEx.Player),
							IsFree:            false,
							WinSmallGame:      0,
							WinTotal:          0,
						}
						sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam)
					}
				}

				//playerEx.PrintBetData(rule.SmallRocketSceneStateBilled)

				playerEx.ReStartGame()

				//playerEx.StopBetCoin()

				SmallRocketSendPlayerInfo(s, playerEx, playerEx.betData, 0, 0)
			}
		}

		// 提前离开的
		for _, playerEx := range sceneEx.PlayerBackup {
			if playerEx != nil && playerEx.isBilled {
				if sceneEx.logic.IsCurRoundBet(playerEx.CurBetData) {
					sceneEx.Statistics(&base.StaticParam{
						SnId:           playerEx.SnId,
						Gain:           playerEx.gainCoin,
						GainTax:        playerEx.taxCoin,
						IsAddTimes:     true,
						HasRobotGaming: sceneEx.robotNum > 0,
					})
				}

				TotalBetValue := sceneEx.logic.GetRoundBetCoin(playerEx.CurBetData)

				// 统计金币变动
				changeCoin := playerEx.gainCoin - playerEx.taxCoin - int64(TotalBetValue)
				startCoin := playerEx.Coin - changeCoin

				// playerEx.SaveSceneCoinLog(startCoin, changeCoin, playerEx.Coin, int64(TotalBetValue), playerEx.taxCoin, playerEx.gainCoin, 0, 0)

				LogBaseResult := model.SmallRocketBaseResultType{}
				LogBaseResult.RoomId = int32(sceneEx.GetSceneId())
				LogBaseResult.TotalBetVal = int64(TotalBetValue)
				LogBaseResult.BeforeCoin = startCoin
				LogBaseResult.AfterCoin = playerEx.Coin
				LogBaseResult.WinCoin = playerEx.gainCoin
				LogBaseResult.PlayerSnid = playerEx.SnId

				if len(playerEx.CurBetData) >= 2 {
					LogBaseResult.BetCoin1 = playerEx.CurBetData[0].BetVal
					LogBaseResult.BetMul1 = playerEx.CurBetData[0].TakeMul
					LogBaseResult.IsAutoBetAndTake1 = playerEx.CurBetData[0].IsAutoBetAndTake
					LogBaseResult.TakeBetMul1 = playerEx.CurBetData[0].GainCoinMul

					LogBaseResult.BetCoin2 = playerEx.CurBetData[1].BetVal
					LogBaseResult.BetMul2 = playerEx.CurBetData[1].TakeMul
					LogBaseResult.IsAutoBetAndTake2 = playerEx.CurBetData[1].IsAutoBetAndTake
					LogBaseResult.TakeBetMul2 = playerEx.CurBetData[1].GainCoinMul
				}

				if !playerEx.IsRob {
					info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult)
					if err == nil {
						sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{})
					}

					totalin := int64(TotalBetValue)
					totalout := playerEx.gainCoin
					validFlow := totalin + totalout
					validBet := common.AbsI64(totalin - totalout)
					logParam := &base.SaveGamePlayerListLogParam{
						Platform:          playerEx.Platform,
						Channel:           playerEx.Channel,
						Promoter:          playerEx.BeUnderAgentCode,
						PackageTag:        playerEx.PackageID,
						InviterId:         playerEx.InviterId,
						LogId:             sceneEx.logid,
						TotalIn:           totalin,
						TotalOut:          totalout,
						TaxCoin:           playerEx.taxCoin,
						BetAmount:         int64(TotalBetValue),
						WinAmountNoAnyTax: playerEx.gainCoin,
						ValidBet:          validBet,
						ValidFlow:         validFlow,
						IsFirstGame:       playerEx.IsPlayerFirst,
						IsFree:            false,
						WinSmallGame:      0,
						WinTotal:          0,
						PlayerName:        playerEx.Name,
					}
					sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam)
				}
			}
		}

		//通知客户端结算结果
		sceneEx.TotalBetPlayer = 0
		//sceneEx.BoomMul = 0
		sceneEx.RoundId++

		s.Gaming = false
	}
}

func (this *StateBilled) OnLeave(s *base.Scene) {
	logger.Logger.Trace("(this *StateBilled) OnLeave, sceneid=", s.GetSceneId())
	this.BaseState.OnLeave(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {

		for _, playerEx := range sceneEx.players {
			if playerEx != nil {
				// 不在线停止自动下注
				if !playerEx.IsOnLine() {
					playerEx.StopLineAutoBetCoin()
					sceneEx.PlayerLeave(playerEx.Player, common.PlayerLeaveReason_DropLine, true)
				}
			}
		}

		if s.CheckNeedDestroy() {
			sceneEx.SceneDestroy(true)
		}
	}
}

func (this *StateBilled) OnTick(s *base.Scene) {
	this.BaseState.OnTick(s)
	if sceneEx, ok := s.ExtraData.(*SceneEx); ok {
		if time.Now().Sub(sceneEx.StateStartTime) > rule.SmallRocketSceneBilledTimeout {
			if sceneEx.CanStart() {

				logger.Logger.Trace("StateStart------SmallRocketSceneBilledTimeout: ", rule.SmallRocketSceneBilledTimeout)
				s.ChangeSceneState(rule.SmallRocketSceneStateStart)
			} else {
				s.ChangeSceneState(rule.SmallRocketSceneStateWait)
			}
			return
		}
	}
}

// // //////////////////////////////////////////////////////////////////////////////
func (this *PolicySmallRocket) RegisteSceneState(state base.SceneState) {
	if state == nil {
		return
	}
	stateid := state.GetState()

	if stateid < 0 || stateid >= rule.SmallRocketSceneStateMax {
		return
	}
	this.states[stateid] = state
}

func (this *PolicySmallRocket) GetSceneState(s *base.Scene, stateid int) base.SceneState {
	if stateid >= 0 && stateid < rule.SmallRocketSceneStateMax {
		return this.states[stateid]
	}
	return nil
}

func init() {
	PolicySmallRocketSingleton.RegisteSceneState(&StateWait{})
	PolicySmallRocketSingleton.RegisteSceneState(&StateStart{})
	PolicySmallRocketSingleton.RegisteSceneState(&PlayGame{})
	PolicySmallRocketSingleton.RegisteSceneState(&StateBilled{})

	core.RegisteHook(core.HOOK_BEFORE_START, func() error {
		base.RegisteScenePolicy(common.GameId_SmallRoket, 0, PolicySmallRocketSingleton)

		return nil
	})
}
