/*
 * 由SharpDevelop创建。
 * 用户： Administrator
 * 日期: 2018-11-20
 * 时间: 10:41
 *
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */

using GameData;
using GameDAL.Backend;
using GameDAL.FriendRoom;
using GameDAL.Game;
using MrWu.Debug;
using Newtonsoft.Json.Linq;
using Server.Data;
using Server.Pack;
using System;
using System.Collections.Generic;
using ObjectModel.User;
using Server.Config;
using GameConfig = Server.Config.GameConfig;

namespace Server
{
    /// <summary>
    /// 游戏服务器逻辑
    /// </summary>
    public class GameDo : IGameData, IGameBehavior<GamePack>
    {
        public virtual bool IsNative => false;
        
        /// <summary>
        /// 下一个处理者
        /// </summary>
        public IGameBehavior<GamePack> NextBehavior
        {
            get { return null; }
        }

        /// <summary>
        /// 是否开战
        /// </summary>
        public bool isWar
        {
            get { return (desk.state & DeskState.War) > 0; }
        }

        /// <summary>
        /// 桌子
        /// </summary>
        protected readonly Desk desk;

        /// <summary>
        /// 打牌的战斗数据key,开战赋值
        /// </summary>
        protected string RedisWarKey;

        /// <summary>
        /// 所在厅的id
        /// </summary>
        protected int tingid
        {
            get { return desk.tingid; }
        }

        /// <summary>
        /// 所在桌子的id
        /// </summary>
        protected int deskid
        {
            get { return desk.id; }
        }

        /// <summary>
        /// 是否是朋友房
        /// </summary>
        protected bool isFriend
        {
            get { return desk.isFriend; }
        }

        /// <summary>
        /// 随机数
        /// </summary>
        protected readonly Random random = new Random();

        /// <summary>
        /// 异常托管时间  可根据游戏不同进行修改
        /// </summary>
        protected virtual int abnormalDepositTime
        {
            get { return 60; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="desk"></param>
        public GameDo(Desk desk)
        {
            this.desk = desk;
            this.desk.DepositChangeHandler = PlayerDepositChange;
        }

        /// <summary>
        /// 当前的玩家数量
        /// </summary>
        protected int plCnt;

        /// <summary>
        /// 座位总数
        /// </summary>
        protected int seatCnts;

        /// <summary>
        /// 是否开战 自己控制
        /// </summary>
        protected bool isFighting { get; set; }

        /// <summary>
        /// 是否存在某个座位
        /// </summary>
        /// <param name="seat"></param>
        /// <returns></returns>
        protected bool ExistsSeat(int seat)
        {
            return seat >= 0 && seat < desk.Count;
        }

        #region 获取游戏或玩家数据

        /// <summary>
        /// 获取座位id
        /// </summary>
        /// <param name="seat">-1表示随机获取一个id</param>
        /// <returns>-1表示未获取到玩家</returns>
        public int GetSeatId(int seat)
        {
            //Debug.Info($"GetSeatId:{seat}");
            if (seat < 0)
            {
                //查找任意一个人
                //Debug.Error("查找任意一个人!");
                int len = desk.Count;
                for (int i = 0; i < len; i++)
                {
                    if (desk[i] != null)
                    {
                        //Debug.Info($"得到SeatId:{desk[i].id}");
                        return desk[i].id;
                    }
                }

                return -1;
            }

            if (seat >= desk.Count || desk[seat] == null)
            {
                return -1;
            }

            //Debug.Info($"得到指定位置Id:{desk[seat].id}");
            return desk[seat].id;
        }


        /// <summary>
        /// 获取玩家的字符串类型信息
        /// </summary>
        /// <param name="seat">玩家座位</param>
        /// <param name="lx">0：玩家昵称,1:玩家注册地区</param>
        /// <returns></returns>
        public string GetPlayerStr(int seat, int lx)
        {
            if (!ExistsSeat(seat))
            {
                Debug.Error("没有这个座位GetPlayerStr:" + seat + "," + lx);
                return string.Empty;
            }

            PlayerDataAsyc pl = desk[seat];
            if (pl == null)
            {
                Debug.Error("GetPlayerStr没有这个玩家:" + seat);
                return string.Empty;
            }

            switch (lx)
            {
                case 0: //玩家昵称
                    return pl.nickname;
                case 1: //玩家注册地区
                    return pl.area;
                case 2: //宠物名称
                    Debug.Error("没有这个字段jasdskjabdk");
                    break;
                default:
                    Debug.Error("存在未解析的字段sadnasjkd");
                    break;
            }

            return string.Empty;
        }

        private int GetPlayerState(PlayerDataAsyc p)
        {
            int result = -1;
            PlayerState ps = (PlayerState)p.state;

            switch (ps)
            {
                case PlayerState.War:
                    if (p.outline == 1 || p.IsDisConnMatch) //离线
                        result = 1;
                    else
                        result = 0;
                    break;
                default:
                    result = 2;
                    break;
            }

            return result;
        }

        /// <summary>
        /// 获取玩家的整形信息
        /// </summary>
        /// <param name="seat">玩家的内存id</param>
        /// <param name="lx">lx 0:获取玩家的台桌id,1:玩家的座位,2:玩家所在的城堡,3:玩家的状态(0正常 1离开[需要代打] 2不在开战中),
        /// 4:玩家的金钱,5:玩家的类型 0普通玩家 1鬼 -1无效id,6:,7:玩家的经验exp,8:,9:玩家的性别,10:玩家的头像,11:,12:,13:玩家的注册id,userid,
        /// 14:玩家的性格,15:,16:玩家所在的厅id,17:是否是手机,18:是否属于切屏状态,19:是否处于托管挂机状态,21:获取玩家是否在托管 1托管 2正常
        /// 22:获取玩家托管时长 单位是秒
        /// 23：获取玩家是否有异常行为 1有 0没有
        /// 24: 获取幸运玩家 10位数字是幸运玩家 个位数字是倒霉玩家  数字从1开始
        /// 25:获取玩家客户端版本</param>
        /// <returns></returns>
        public virtual int GetPlayerInt(int seat, int lx)
        {
            if (!ExistsSeat(seat))
            {
                Debug.Error("没有这个座位GetPlayerInt:" + seat + "," + lx);
                return -1;
            }

            PlayerDataAsyc pl = desk[seat];
            if (pl == null)
            {
                Debug.Error("GetPlayerInt没有这个玩家:" + seat + "," + lx);
                return -1;
            }

            switch (lx)
            {
                case 0: //玩家台桌id
                    return pl.deskid;
                case 1: //玩家座位
                    return pl.seat;
                case 2: //玩家真实房间id
                    //Debug.Log("获取玩家房间号:" + pl.roomid + "," + pl.userid);
                    return pl.roomid;
                case 3: //玩家状态  返回 0正常 1离开(需要代打) 2不在开战中
                    return GetPlayerState(pl);
                case 4: //玩家金钱 Money
                    // Debug.Log("获取玩家金钱:" + pl.money + "," + pl.userid + "," + pl.seat);
                    if (pl.money > playerData.MaxMoney)
                        return playerData.MaxMoney;
                    return (int)pl.money;
                case 5: //玩家类型 返回 0普通玩家 1鬼  -1无效id
                    if (pl.userid > 0)
                        return 0;
                    if (pl.userid < -1000)
                        return 1;
                    Debug.Log(pl.userid);
                    return -1;
                case 6: //玩家虚拟(显示)房间id
                    Debug.Error("没有虚拟房间这个字段了!!!");
                    break;
                case 7: //玩家经验 Exp
                    return pl.exp;
                case 8: //玩家魅力 Charm
                    //Debug.Warning("没有玩家魅力这个字段了!");
                    break;
                case 9: //玩家性别 Sex
                    return pl.sex;
                case 10: //玩家头像 PhotoID
                    //Debug.Warning("没有玩家头像id这个字段了!");
                    break;
                case 11: //玩家衣服 Clothes
                    //Debug.Warning("暂时没有玩家衣服字段,待补充!");
                    break;
                case 12: //宠物id
                    //Debug.Warning("暂时没有玩家宠物id这个字段!");
                    break;
                case 13: //玩家注册id UserID
                    //if (pl.userid < 0)
                    //    Debug.Warning("注意鬼id的使用!");
                    return pl.userid;
                case 14: //获取性格
                    return pl.mettle;
                case 15: //返回牛人等级
                    //Debug.Warning("暂时没有牛人等级!");
                    return 0;
                case 16: //房间的厅id
                    //Debug.Warning("注意使用厅id");
                    return pl.tingid;
                case 17: //是否手机
                    // Debug.Warning("暂时没有手机这个字段!");
                    break;
                case 18: //是否切屏
                    // Debug.Warning("暂时没有是否切屏这个字段!");
                    return 0;
                case 19: //托管挂机
                    return pl.isGuaji ? 1 : 0;
                case 20: //是否已提前结算
                    Debug.Warning("注意提前结算的使用!");
                    return 0;
                case 21: //返回是否在托管 1托管 2没有托管
                    if (pl.isRobot) return 2;
                    //Debug.Log($"获取 玩家userid:{pl.userid}  托管状态：{(pl.isDePosit ? "托管中" : "正常")}");
                    return pl.isDePosit ? 1 : 2;
                case 22: //返回玩家托管时长 单位是秒
                    if (pl.isRobot) return 0;
                    int num = pl.DePositSecon;
                    if (pl.isDePosit && pl.DePositTime != default(DateTime))
                    {
                        //如果玩家这个时候还在托管就把从托管到现在的时间计算出来并加上返回
                        num += (int)DateTime.Now.Subtract(pl.DePositTime).TotalSeconds;
                    }

                    //Debug.Log($"获取 玩家userid:{pl.userid} nickname:{pl.nickname} 托管时长：{num}");
                    return num;
                case 23: //判断是否是异常行为是：托管次数大于1次，时长大于59秒
                    if (pl.isRobot) return 0;
                    int n = pl.DePositSecon;
                    if (pl.isDePosit && pl.DePositTime != default(DateTime))
                    {
                        n += (int)DateTime.Now.Subtract(pl.DePositTime).TotalSeconds;
                    }

                    var b = n >= abnormalDepositTime || pl.DePositCount >= 2;
                    Debug.Info(
                        $"玩家获取 玩家userid:{pl.userid} nickname:{pl.nickname} 托管次数：{pl.DePositCount}，托管时长：{n} 是否是异常行为:{(b ? "是" : "不是")}");
                    return b ? 1 : 0;

                case 25: //获取客户端版本号
                    return pl.ClientVer;
                case 24: //获取幸运座位
                    return GetLuckSeat();
                case 26:    //获取玩家是否离线
                    return pl.outline;
                default:
                    Debug.Warning("存在未解析的类型:" + lx);
                    break;
            }

            return -1;
        }

        /// <summary>
        /// 获取玩家是否是异常
        /// </summary>
        /// <param name="pl"></param>
        /// <returns>1是异常 0不是异常</returns>
        public int GetPlayYc(PlayerDataAsyc pl)
        {
            if (pl == null || pl.isRobot) return 0;
            int n = pl.DePositSecon;
            if (pl.isDePosit && pl.DePositTime != default(DateTime))
            {
                n += (int)DateTime.Now.Subtract(pl.DePositTime).TotalSeconds;
            }

            var b = n >= 60 || pl.DePositCount >= 2;
            return b ? 1 : 0;
        }

        private List<int> tempList = new List<int>();

        /// <summary>
        /// 获取幸运座位 10位数字是幸运玩家 个位数字是倒霉玩家
        /// </summary>
        /// <returns>这个座位是从1开始</returns>
        public int GetLuckSeat()
        {
            if (desk.deskinfo == null || desk.deskinfo.creatStyle != 5 || string.IsNullOrEmpty(desk.deskinfo.wayid))
            {
                return 0;
            }
            
            tempList.Clear();
            for (int i = 0; i < desk.Count; i++)
            {
                if (desk[i] != null)
                {
                    tempList.Add(desk[i].userid);
                }
                else
                {
                    tempList.Add(0);
                }
            }

            var tuple = LuckPlayerManager.Instance.GetLuckValueIndex(desk.deskinfo.wayid,tempList);
            return (tuple.Item1 + 1) * 10 + tuple.Item2 + 1;
        }
        
        /// <summary>
        /// 获取桌子字符串信息
        /// </summary>
        /// <param name="lx">lx:5获取当前朋友房的规则字符串,</param>
        /// <returns></returns>
        public string GetDeskStr(int lx)
        {
            return desk.GetStringValue(lx.ToString());
        }

        /// <summary>
        /// 获取台桌的整数信息
        /// </summary>
        /// <param name="lx">lx:1:桌上当前人数 4:当前桌子用的是第几个规则, 也就是厅的id 5:桌子是否在开战中 7:当前桌子是否是朋友房的桌子 8:朋友房已完成局数 9:当前正在进行的是第几局 从0开始 10:是否是vip房间 11:朋友房创建者的id 12:朋友房要完成的局数 13:座位数量 14:朋友房创建的类型 0普通开 1代开房间 5竞技比赛创建房间</param>
        /// <returns></returns>
        public int GetDeskInt(int lx)
        {
            return desk.GetIntValue(lx.ToString());
        }

        /// <summary>
        /// 获取厅的字符串信息
        /// </summary>
        /// <param name="lx"></param>
        /// <returns></returns>
        public string GetTingStr(int lx)
        {
            var ting = GameManager.instance.FindTing(tingid);

            switch (lx)
            {
                case 0: //获取厅的所有规则
                    return ting.config.TingGz;
            }

            Debug.Warning("没有啥厅字符串信息" + lx);
            return string.Empty;
        }

        /// <summary>
        /// 获取厅信息
        /// </summary>
        /// <param name="lx">lx: 0:预先创建的桌子数量, 1:最小开战人数, 2:最大开战人数, 3:, 4:获取厅的游戏币输赢值是对100取整的 </param>
        /// <returns></returns>
        public int GetTingInt(int lx)
        {
            TingManager ting = GameManager.instance.FindTing(tingid);
            switch (lx)
            {
                case 0: //桌子数量 0表示动态生成桌子  >0表示预先生成桌子!
                    if (ting.config.DeskCnt <= 0)
                        return 0;
                    return ting.config.DeskCnt;
                case 1: //最小开战人数
                    return ting.config.MinPlayerCnt;
                case 2: //最大开战人数
                    return ting.config.MaxPlayerCnt;
                case 3: //游戏模式
                    Debug.Error("转至游戏配置!");
                    break;
                case 4: //获取厅的输赢
                    int money = (int)(ting.winmoney / 100);
                    Debug.Log("获取厅赢的钱:" + money);
                    return money;
                case 5: //获取厅id
                    return tingid;
                default:
                    Debug.Error("为解析的厅信息:" + lx);
                    break;
            }

            return -1;
        }

        /// <summary>
        /// 获取厅数据
        /// </summary>
        public object GetTingData(string tag)
        {
            var ting = GameManager.instance.FindTing(tingid);

            return ting.GetData(tag);
        }

        /// <summary>
        /// 获取房间数据
        /// </summary>
        /// <param name="roomid">房间id</param>
        /// <param name="tag">标记</param>
        /// <returns></returns>
        public object GetRoomData(int roomid, string tag)
        {
            var room = GameManager.instance.FindRoom(roomid);

            return room.GetData(tag);
        }

        /// <summary>
        /// 获取房间字符串信息
        /// </summary>
        /// <param name="roomid"></param>
        /// <param name="lx"></param>
        /// <returns></returns>
        public string GetRoomStr(int roomid, int lx)
        {
            RoomManager room = GameManager.instance.FindRoom(roomid);
            if (room == null)
            {
                Debug.Error("获取房间失败,没有这个房间:" + roomid);
                return string.Empty;
            }

            return room.GetStringValue(lx.ToString());
        }

        /// <summary>
        /// 获取房间的整数型信息
        /// </summary>
        /// <param name="roomid">房间id</param>
        /// <param name="lx">0:房间赔率 2:房间模式 0普通模式 1百家乐模式 3:收税 4:经验加成 5:整个服务器输赢</param>
        /// <returns></returns>
        public int GetRoomInt(int roomid, int lx)
        {
            RoomManager room = GameManager.instance.FindRoom(roomid);
            if (room == null)
            {
                Debug.Error("获取房间失败，没有这个房间:" + roomid);
                return -1;
            }

            return room.GetIntValue(lx.ToString());
        }

        /// <summary>
        ///获取朋友房规则!
        /// </summary>
        /// <returns></returns>
        public string GetRoomGz()
        {
            if (!desk.isFriend)
                return string.Empty;
            return desk.deskinfo.rule.roomrule;
        }

        #endregion

        #region 设置玩家或者游戏数据

        /// <summary>
        /// 计算实际输赢子
        /// 只适合没有替身的金币场结算
        /// </summary>
        /// <param name="playerScores"></param>
        /// <returns></returns>
        public virtual void TongJiPlayer(List<Tuple<int,int>> playerScores)
        {
            List<Tuple<int, long>> temp = new List<Tuple<int, long>>(){ };
            List<int> winSeats = new List<int>();
            List<int> lostSeats = new List<int>();
            for (int i = 0; i < playerScores.Count; i++)
            {
                if (playerScores[i].Item2 >= 0)
                {
                    winSeats.Add(playerScores[i].Item1);
                }
                else
                {
                    lostSeats.Add(playerScores[i].Item1);
                }
                int seat = playerScores[i].Item1;
                PlayerDataAsyc player = desk[seat];
                int beilv = GameManager.instance.FindRoom(player.roomid).config.BeiLv;
                long winMoney = playerScores[i].Item2 * beilv;
                temp.Add(new Tuple<int, long>(playerScores[i].Item1, winMoney));
            }
            for (int i = 0; i < playerScores.Count; i++)
            {
                int seat = playerScores[i].Item1;
                PlayerDataAsyc player = desk[seat];
                long money = player.money;
                int beilv = GameManager.instance.FindRoom(player.roomid).config.BeiLv;
                long winMoney = playerScores[i].Item2 * beilv;
                if (money < -winMoney)
                {
                    long remian = money - winMoney;
                    //输家少输
                    long every = remian / lostSeats.Count;
                    for (int j = 0; j < lostSeats.Count; j++)
                    { 
                        int index = temp.FindIndex(x=>x.Item1 == lostSeats[j]);
                        long tempMoney = temp[index].Item2;
                        temp[index] = new Tuple<int, long>(temp[index].Item1, tempMoney + every);
                    }
                    temp[i] = new Tuple<int, long>(playerScores[i].Item1, -money);   
                }
                else if(winMoney > money)
                {
                    long remian = winMoney - money;
                    //赢家少赢
                    long every = remian / winSeats.Count;
                    for (int j = 0; j < winSeats.Count; j++)
                    {
                        int index = temp.FindIndex(x => x.Item1 == winSeats[j]);
                        long tempMoney = temp[index].Item2;
                        temp[index] = new Tuple<int, long>(temp[index].Item1, tempMoney - every);
                    }
                    temp[i] = new Tuple<int, long>(playerScores[i].Item1, money);
                }
            }

            for (int i = 0; i < temp.Count; i++)
            {
                int seat = temp[i].Item1;
                PlayerDataAsyc player = desk[seat];
                IncGoldDeskMoney(player, temp[i].Item2);
            }
        }
        
        /// <summary>
        /// 设玩家数据
        /// </summary>
        /// <param name="seat">玩家的座位</param>
        /// <param name="lx">0:设置玩家金钱,1:增加玩家金钱 (0与1是游戏中途的结算) 2:与0类似， 3:与1类似 (2与3是游戏结束的结算) (2与3是会触发经验，与魅力的结算) 5:给鬼加钱。 6:增加玩家经验  8,9:朋友房间结算(8设置玩家分值,9是增加玩家分值) 10: 11, 12:使用幸运玩家 13:使用倒霉玩家</param>
        /// <param name="num"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public virtual int SetPlayer(int seat, int lx, int num, string str)
        {
#if DEBUG
            Debug.Info($"game setPlayer seat:{seat} - lx:{lx} - num: {num}");
#endif


            if (!ExistsSeat(seat))
            {
                Debug.Error("没有这个座位SetPlayer:" + seat + "," + lx + "," + num + "," + str);
                return -1;
            }

            PlayerDataAsyc pl = desk[seat];
            if (pl == null)
            {
                Debug.Error("这个位置上没有人 SETPLAYER" + seat + ",lx:" + lx);
                return -1;
            }

            GameConfig gameConfig = ServerConfigManager.Instance.GameConfig;
            switch (lx)
            {
                case 0: //设置玩家金钱   //1,2 不算赔率，直接加减
                case 1: //游戏中玩家金钱
                    if (gameConfig.GameMode == 1)
                    {
                        if (pl.userid > 0)
                            Debug.ImportantLog(
                                $"玩家下注钱-deskid:{pl.deskid},userid:{pl.userid},money:{pl.money},num:{num},seat:{seat}");
                    }

                    IncMoney(pl, lx, num);
                    break;

                case 2: //结算玩家金钱(基数)  //2,3算赔率  加经验,魅力(这个不要)  发送给比赛服务器  //如果钱大于20亿就把   20亿存成金币
                case 3: //游戏中玩家金钱(基数)

                    if (gameConfig.GameMode == 1)
                    {
                        if (pl.userid > 0)
                            Debug.ImportantLog($"玩家结算钱-userid:{pl.userid},num:{num}");
                    }

                    IncMoney(pl, lx, num);
                    break;

                case 4: //记录收税

                    if (gameConfig.GameMode == 1)
                    {
                        if (pl.userid > 0)
                        {
                            if (num < 0)
                            {
                                break;
                            }

                            if (pl.roomid < 0 || pl.roomid >= GameManager.instance.roomCnt)
                            {
                                Debug.Error("玩家数据错误，没找到房间:" + pl.userid + "," + pl.nickname + "," + pl.roomid);
                                break;
                            }

                            var room = GameManager.instance.FindRoom(pl.roomid);


                            Debug.Info("税收:" + pl.userid + "," + num);

                            //此处要注意-如果出了可以输赢小于100金额的税 就计算不准确
                            int tax = (int)((long)room.config.Tax * num / 100);

                            room.AddTaxMoney(tax);

                            if (tax > 20000000)
                            {
                                Debug.Warning("一局的税收这么大???????" + tax + "," + num);
                            }

                            if (pl.tingid < 0 || pl.tingid >= GameManager.instance.tingCnt)
                            {
                                Debug.Error("玩家数据错误,没找到厅:" + pl.userid
                                                           + "," + pl.nickname + "," + pl.tingid);
                                break;
                            }

                            var ting = GameManager.instance.FindTing(tingid);
                            ting.AddTaxMoney(tax);
                        }
                    }
                    else
                    {
                        Debug.Error("不是百家乐不能从此处收税!");
                    }

                    break;

                case 5: //给PE加钱并换名字
                    if (pl.isRobot)
                        pl.money += num;
                    else
                        Debug.Error("游戏内部不可以给玩家加钱:" + pl.userid + "," + pl.money + "," + seat);
                    break;

                case 6: //:加经验
                    if (pl.isRobot) break;
                    if (gameConfig.GameMode != 1) break;
                    AddExp(pl, num);
                    break;

                case 7: //小魏百家乐踢人
                    Debug.Error("牛牛踢人:" + seat + "," + lx + "," + num + "," + str);
                    break;

                case 8: //朋友房结算 最终
                case 9: //朋友房结算 增量
                    Debug.Info("设置朋友房结算:"+pl.userid + "," + lx + "," + num + "," + pl.seat);
                    IncMoney(pl, lx, num);
                    break;

                case 10: //设置提前结算=true
                    break;
                case 11: //提前下桌
                    break;
                case 12:// 设置幸运玩家，
                    Debug.Error("这个函数不用了 setPlayer(lx 12)");
                    break;
                case 13:// 设置倒霉玩家
                    Debug.Error("这个函数不用了 setPlayer(lx 13)");
                    break;
                default:
                    Debug.Error("收到未解析的玩家数据asjdhkjsad");
                    return 0;
            }

            return 1;
        }

        /// <summary>
        /// 添加经验
        /// </summary>
        private void AddExp(PlayerDataAsyc pl, int exp)
        {
            pl.exp += exp;
            pl.expChange += exp;
            Debug.Info("经验加成:" + pl.userid + "," + exp);
        }
        
        /// <summary>
        /// 游戏结算处理玩家游戏币
        /// </summary>
        /// <param name="pl">玩家</param>
        /// <param name="lx">类型 0设置玩家金钱 1游戏中玩家金钱 2结算子 3游戏子  8朋友房最终 9朋友房增量</param>
        /// <param name="num">变化的游戏币</param>
        private void IncMoney(PlayerDataAsyc pl, int lx, int num)
        {
            Debug.Log("游戏币修改 seat:" + pl.seat + " - lx:" + lx + " - num:" + num);

            //8是最终 9是增量
            if (lx == 8 || lx == 9) //朋友房结算
            {
                if (tingid != GameManager.instance.friendTing.id)
                {
                    Debug.Error("玩家没在朋友房游戏中，为啥调用朋友房的结算!");
                    return;
                }

                desk.IncMoney(pl.seat, lx, num);
                return;
            }

            long peilv;
            long money;

            //先算替身
            if (string.IsNullOrEmpty(pl.friendWeiYiMa))
            {
                //金币房替身结算

                if (pl.shadows != null)
                {
                    int len = pl.shadows.Length;
                    for (int i = 0; i < len; i++)
                    {
                        peilv = GameManager.instance.FindRoom(i).config.BeiLv;
                        money = num;
                        if (lx == 2 || lx == 3)
                            money = (long)num * peilv;
                        //加钱
                        // Debug.Log("替身加钱num:{0},money:{1}", num, money);
                        IncMoney(pl.shadows[i], money, false);
                    }
                }
                else
                {
                    Debug.Error("玩家没有替身:" + pl.userid);
                }
            }

            //结算本人
            if (pl.MatchObj != null)
            {
                peilv = pl.RaceBeiLv;
            }
            else
            {
                peilv = GameManager.instance.FindRoom(pl.roomid).config.BeiLv;
            }


            money = num;
            if (lx == 2 || lx == 3)
                money = (long)num * peilv;

            if (pl.userid > 0)
            {
                PropManager.Instance.AddGoldLog(pl.userid,money, pl.money + money, UserGoldLogType.Private_GamePlay, "游戏结算");
            }
            
            //Debug.Log("本人加减钱num:{0},money:{1}", num, money);
            pl.WarMoney += money;
            IncMoney(pl, money, !pl.isRobot);
            if (!pl.isRobot && pl.WarData != null)
            {
                //统计玩家的游玩盘数和胜负率
                pl.WarData.GameTotal++;
                pl.WarData.TotalChange++;
                if (num > 0)
                {
                    pl.WarData.WinCount++;
                    pl.WarData.WinChange++;
                }
                else
                {
                    pl.WarData.LoseChange++;
                    pl.WarData.LoseCount++;
                }

                var yc = GetPlayYc(pl);
                if (yc == 1)
                {
                    pl.WarData.ExcepCount++;
                }

                if (pl.WarData.GameTotal == 2 && pl.TuiGuangLeve > 0 && pl.WarData.ExcepCount > 0)
                {
                    Debug.Error(
                        $"玩家满足了任意2局游戏可以获得推广奖励，但是有异常托管{pl.WarData.ExcepCount}，取消奖励 userid:{pl.userid},platTag:{pl.platTag}");
                }

                if (pl.WarData.GameTotal == 2 && pl.TuiGuangLeve > 0 && pl.WarData.ExcepCount == 0)
                {
                    //  RewardsDal.SaveReward(pl.TuiGuangUser.userid, 1, 1, 100, GameBase.gamebase.config.modeuleInfo.id, pl.userid,1);
                }
            }

            //计算服务器输赢钱
            if (pl.roomid < 0 || pl.roomid >= GameManager.instance.roomCnt)
            {
                Debug.Error("玩家的房间数据有问题:" + pl.roomid + "," + pl.userid + "," + pl.nickname);
                return;
            }

            var room = GameManager.instance.FindRoom(pl.roomid);
            if (!pl.isRobot)
            {
                if (num > 0 && ServerConfigManager.Instance.GameMode != 1)
                    AddExp(pl, room.config.Exp);

                room.AddWinMoney(-money);

                if (pl.tingid < 0 || pl.tingid >= GameManager.instance.tingCnt)
                {
                    Debug.Error("玩家的厅数据有问题:" + pl.tingid + "," + pl.userid + "," + pl.nickname);
                    return;
                }

                var tmpting = GameManager.instance.FindTing(pl.tingid);

                desk.AddWinMoney(-money);
            }
        }


        /// <summary>
        /// 触发加减钱
        /// </summary>
        /// <param name="pl">玩家</param>
        /// <param name="money">游戏币变化值</param>
        /// <param name="person">是否是真人</param>
        protected void IncMoney(PlayerDataAsyc pl, long money, bool person = false)
        {
            if (money < 0 && pl.money < Math.Abs(money))
            {
                money = -(int)pl.money;
            }

            //要判断有没有超过最大金额数
            pl.money += money;

            if (pl.money < 0)
            {
                Debug.Error($"玩家钱输成负数,name:{pl.nickname},userid:{pl.userid},money:{pl.money},money:{money}");
            }

            if (person)
            {
                //真人发包给数据服务器修改数据
                pl.moneyChange += money;
                pl.WinMoney += money;
            }
        }


        /// <summary>
        /// 金币场游戏结算处理玩家游戏币
        /// </summary>
        /// <param name="player"></param>
        /// <param name="money"></param>
        public void IncGoldDeskMoney(PlayerDataAsyc pl, long money)
        {

            //金币房替身结算
            if (pl.shadows != null)
            {
                int len = pl.shadows.Length;
                for (int i = 0; i < len; i++)
                {
                    long tempMoney = money / pl.money * pl.shadows[i].money;
                    //加钱
                    IncMoney(pl.shadows[i], tempMoney, false);
                }
            }
            else
            {
                Debug.Error("玩家没有替身:" + pl.userid);
            }

            if (pl.userid > 0)
            {
                PropManager.Instance.AddGoldLog(pl.userid,money, pl.money + money, UserGoldLogType.Private_GamePlay, "游戏结算");
            }
            
            //Debug.Log("本人加减钱num:{0},money:{1}", num, money);
            IncMoney(pl, money, !pl.isRobot);
            if (!pl.isRobot && pl.WarData != null)
            {
                //统计玩家的游玩盘数和胜负率
                pl.WarData.GameTotal++;
                pl.WarData.TotalChange++;
                if (money > 0)
                {
                    pl.WarData.WinCount++;
                    pl.WarData.WinChange++;
                }
                else
                {
                    pl.WarData.LoseChange++;
                    pl.WarData.LoseCount++;
                }
                var yc = GetPlayYc(pl);
                if (yc == 1)
                {
                    pl.WarData.ExcepCount++;
                }
            }

            //计算服务器输赢钱
            if (pl.roomid < 0 || pl.roomid >= GameManager.instance.roomCnt)
            {
                Debug.Error("玩家的房间数据有问题:" + pl.roomid + "," + pl.userid + "," + pl.nickname);
                return;
            }
            var room = GameManager.instance.FindRoom(pl.roomid);
            if (!pl.isRobot)
            {
                if (money > 0 && ServerConfigManager.Instance.GameMode != 1)
                    AddExp(pl, room.config.Exp);

                room.AddWinMoney(-money);
                if (pl.tingid < 0 || pl.tingid >= GameManager.instance.tingCnt)
                {
                    Debug.Error("玩家的厅数据有问题:" + pl.tingid + "," + pl.userid + "," + pl.nickname);
                    return;
                }
                desk.AddWinMoney(-money);
            }

        }

        /// <summary>
        /// 保存朋友房数据
        /// </summary>
        public int SaveData(byte[] data)
        {
            if (desk.deskinfo == null || desk.deskinfo.isAllOver)
            {
                Debug.Error("只有朋友房支持保存牌局数据!");
                return -1;
            }

            string weiyima = desk.deskinfo.weiyima;
            Room.SaveFightData(weiyima, data);
            return 1;
        }

        /// <summary>
        /// 保存回放数据
        /// </summary>
        /// <param name="lx">回放数据的类型</param>
        /// <param name="jsondata">回放数据</param>
        public void SaveHuiFang(int lx, string jsondata)
        {
            if (desk.deskinfo == null)
            {
                Debug.Error("开启朋友房才需要保存回放");
            }
            if (string.IsNullOrEmpty(jsondata)) return;
            if (desk.state != DeskState.War) return;
            if (desk.fightdata == null)
                desk.fightdata = new FightData();
            fightdataone onedata = new fightdataone() { lx = lx, data = jsondata };

            //先暂存在 内存和redis中
            desk.fightdata.fightPack.Add(onedata);
            //Room.SaveFightRecord(desk.deskinfo.weiyima, desk.deskinfo.burs.Count, onedata);
        }

        /// <summary>
        /// 给算法用的，保存其他数据, 暂时只给朋友房用,实际上金币场也可以用,后面优化
        /// </summary>
        /// <param name="base64data">台桌数据</param>
        /// <returns>0保存失败 1保存成功</returns>
        public int SaveOtherData(string base64data)
        {
            if (desk.deskinfo == null)
            {
                //Debug.Error("保存其他数据失败，非朋友房暂不支持保存此数据!");
                return 0;
            }

            //Debug.Log("保存数据:" + base64data);
            desk.deskinfo.otherdata = base64data;
            return 1;
        }

        /// <summary>
        /// 加载台桌数据-牌局共享数据
        /// </summary>
        /// <returns>台桌数据</returns>
        public string LoadOtherData()
        {
            if (desk.deskinfo == null)
                return "";

            Debug.Info("来加载数据:" + desk.deskinfo.otherdata);
            return desk.deskinfo.otherdata;
        }

        /// <summary>
        /// 扣税
        /// </summary>
        /// <param name="pl"></param>
        protected virtual void DedShui(PlayerDataAsyc pl)
        {
            //先扣替身钱
            for (int i = 0; i < GameManager.instance.roomCnt; i++)
            {
                int money = GameManager.instance.FindRoom(i).config.Tax;
                if (pl.shadows[i] == null)
                {
                    Debug.Error("玩家的影子竟然是空!!!");
                    continue;
                }

                IncMoney(pl.shadows[i], -money, false);
            }

            if (!pl.isRobot)
            {
                //触发游戏数据更新
                var room = GameManager.instance.FindRoom(pl.roomid);

                if (room == null)
                {
                    Debug.Error("玩家房间数据错误:" + pl.roomid + "," + pl.userid + "," + pl.nickname);
                    return;
                }

                int tax = room.config.Tax;
                pl.Pan++;
                if (GameManager.instance.IsWriteKouShuiLog(pl))
                {
                    PropManager.Instance.AddGoldLog(pl.userid,-tax, pl.money - tax, UserGoldLogType.Private_GameTax, "税收");
                }

                IncMoney(pl, -tax, true);
                room.AddTaxMoney(tax);

                var desk = GameManager.instance.FindDesk(pl.tingid, pl.deskid);
                if (desk == null)
                {
                    Debug.Error("玩家厅或桌子数据错误:" + pl.tingid + "," + pl.deskid + "," + pl.userid + "," + pl.nickname);
                    return;
                }

                desk.AddTaxMoney(tax);
            }
        }

        #endregion

        #region 发包

        /// <summary>
        /// 发包
        /// </summary>
        /// <param name="seat">对谁发 -1表示发全桌 其他是对某个座位发</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public virtual int SendPack(int seat, byte[] data)
        {
            desk.SendZyxPack(seat, data,IsNative);

            return 1;
        }

        #endregion

        #region 行为

        protected virtual void OtherGameDataInit()
        {
            desk.DeskOtherData.IsUsingHandTacker = new bool[plCnt];
            desk.SendOtherData(-1);
        }

        /// <summary>
        /// 开战
        /// </summary>
        public virtual void StartWar()
        {
            Debug.Info("GameDo StartWar");
            RedisWarKey =
                $"{ServerConfigManager.Instance.NodeId}:{desk.id}{DateTime.Now.ToString("yyyyMMddHHmmss")}"; //战斗数据的Redis Key
            plCnt = GetDeskInt(1);
            seatCnts = GetDeskInt(13);
            isFighting = true;

            OtherGameDataInit();
            
            if (!isFriend)
            {
                foreach (var pl in desk)
                {
                    if (pl == null) continue;
                    RestDePosit(pl);
                    DedShui(pl);
                }
            }
        }

        /// <summary>
        /// 重置托管时间
        /// </summary>
        /// <param name="pl"></param>
        void RestDePosit(PlayerDataAsyc pl)
        {
            if (pl == null) return;
            pl.SetDeposit(pl.outline == 1);
            pl.DePositTime = pl.isDePosit ? DateTime.Now : default(DateTime);
            pl.DePositSecon = 0;
            pl.DePositCount = 0;
        }


        protected bool IsDeposit(int seat)
        {
            if (seat < 0 || seat >= desk.PlayerCnt)
            {
                return false;
            }

            var pl = desk[seat];
            return pl != null && pl.isDePosit;
        }

        /// <summary>
        /// 获取第一个托管的座位
        /// </summary>
        /// <returns></returns>
        public int GetPlayerFirstDepositSeat()
        {
            if (desk.DepositUserIds == null || desk.DepositUserIds.Count == 0)
            {
                return -1;
            }

            int userid = desk.DepositUserIds[0];
            Debug.Info($"得到第一个托管的人:{userid}");
            return desk.FindPlayer(userid);
        }

        /// <summary>
        /// 游戏超时做的逻辑
        /// </summary>
        /// <returns>True 可以踢玩家 false 不能踢
        /// 金币场的是可以踢的，比赛的桌子有比赛的逻辑
        /// </returns>
        public virtual bool TimeOutWarOver()
        {
            Debug.ImportantLog("游戏超时！ gamedo");
            return true;
        }

        /// <summary>
        /// 重连
        /// </summary>
        public virtual void Reconnect(int seat)
        {
        }

        /// <summary>
        /// 超时惩罚
        /// </summary>
        /// <param name="seat"></param>
        public virtual void OverTimePenalty(int seat)
        {
        }

        #region ITimerProcessor

        /// <summary>
        /// 定时器
        /// </summary>
        public virtual void OnTime(int interval)
        {
        }

        /// <summary>
        /// 秒级定时器
        /// </summary>
        void ITimerProcessor.SecondTime()
        {
        }

        #endregion

        /// <summary>
        /// 加载桌子数据 用户恢复桌子
        /// </summary>
        /// <param name="data"></param>
        public virtual void LoadMem(byte[] data,bool isOld)
        {
        }

        public virtual void LoadMemSuccess()
        {
        }

        /// <summary>
        /// 某玩家离线
        /// </summary>
        /// <param name="seat"></param>
        public virtual void OutLine(int seat)
        {
            Debug.Log("玩家离线:" + seat);
        }

        /// <summary>
        /// 某玩家退出
        /// </summary>
        /// <param name="seat"></param>
        public virtual void Quit(int seat)
        {
            Debug.Log("有玩家退出桌子!" + seat);
        }

        /// <summary>
        /// 游戏结束
        /// </summary>
        public virtual void WarOver()
        {
            foreach (var pl in desk)
            {
                if (pl == null) continue;
                RestDePosit(pl);
                //desk.SendAllPlayerInfo(pl);
            }

            desk.WarOver();
            isFighting = false;
        }

        /// <summary>
        /// 房间被解散
        /// </summary>
        /// <param name="style"></param>
        public virtual void DisBank(int style = -1)
        {
        }

        /// <summary>
        /// 这个玩家是否可以离开
        /// </summary>
        /// <param name="seat"></param>
        /// <returns></returns>
        public virtual bool CanQuit(int seat)
        {
            //一般来说，未开战就可以离开
            return ((desk.state & DeskState.War) == 0);
        }

        /// <summary>
        /// 设置玩家的操作权
        /// </summary>
        /// <param name="seat"></param>
        /// <param name="waitOperation"></param>
        public void SetPlayerWaitOperation(int seat, bool waitOperation)
        {
            if (seat < 0 || seat >= desk.PlayerCnt)
            {
                return;
            }

            var pl = desk[seat];
            if (pl != null)
            {
                //之前不能操作,现在可以操作，重置托管时间
                if (!pl.WaitOperation && waitOperation)
                {
                    pl.AutoDepositTime = 0;
                }

                pl.WaitOperation = waitOperation;
            }
        }

        #region IGameMessage

        /// <summary>
        /// 处理包
        /// </summary>
        public virtual void DoZyxPack(GamePack pack)
        {
        }

        public virtual bool DoChatPack(GamePack pack)
        {
            return true;
        }

        /// <summary>
        /// 处理聊天包裹
        /// </summary>
        /// <param name="pack"></param>
        /// <returns>-2 是不发 -1 是全发 大于等于0 是指定发</returns>
        public virtual int DoChatNewPack(GamePack pack)
        {
            return -1;
        }

        /// <summary>
        /// 处理道具包
        /// </summary>
        /// <param name="pack"></param>
        /// <returns>-1 发送给全员  -2 不发 大于等于0 指定位置发</returns>
        public virtual int DoProps(PropsPack pack)
        {
            if (pack == null || pack.sendId <= 0 || pack.PropsId <= 0 || pack.Count <= 0)
            {
                return -2;
            }

            for (int i = 0; i < desk.PlayerCnt; i++)
            {
                if (desk[i] == null) continue;
                if (desk[i].userid == pack.sendId)
                {
                    var temp = GameData.PropsConfig.list.Find(x => x.PropsId == pack.PropsId);
                    if (temp == null)
                    {
                        return -2;
                    }

                    if (desk[i].money <= pack.Count * temp.Money) return -2; //身上的钱不够扣
                    IncMoney(desk[i], -(pack.Count * temp.Money), true);
                    return -1;
                }
            }

            return -2;
        }

        protected virtual void PlayerDepositChange(int seat)
        {
            
        }

        #endregion

        #endregion
    }

    /*
     * initMem 删除初始化内存的方法
     * DoZyxFun 删除DoZyxFun方法
     * CanQuit 新增玩家中途离开时，询问游戏是否可以离开的方法
     * */
}