%% -----------------------------------------------------
%% @author  :ljy
%% moudle   :custom_act_reversi.erl
%% desc     :黑白棋抽奖
%% time     :2020.11.23
%% ------------------------------------------------------
-module(custom_act_reversi).

-include("reversi.hrl").
-include("custom_act.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("goods.hrl").

-export([
    get_pool_info/2         %% 获取总奖池信息
    , get_lottery_info/2    %% 获取抽奖奖池信息
    , get_display_info/2    %% 展示的小奖池信息
    , refresh_pool/3        %% 刷新奖池
    , lottery/2             %% 抽奖
    , gm_reset_route/3      %% 指定路线
    , gm_check_route/0      %% 校验所有路线是否正确
    , gm_reset_data/2       %% 重置活动数据
]).

%% 获取总奖池信息
get_pool_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_act_status(SubType, RoleId, Lv) of
        {Condition, _CustomData, ActData} ->
            case lottery_cost(Condition) of
                false ->
                    {false, ?ERRCODE(missing_config)};
                Cost ->
                    #reversi_data{score = Score, free_times = FreeTimes} = ActData,
                    F = fun(GradeId, Acc) ->
                        case data_reversi:get_reward_info(SubType, GradeId) of
                            #reversi_reward{type = Type, lucky = [MinScore, MaxScore], role_lv = [MinLv, MaxLv], reward = Reward} ->
                                if
                                    Type =:= 1 andalso Lv >= MinLv andalso Lv =< MaxLv ->
                                        [{GradeId, Type, MinScore, MaxScore, util:term_to_string(Reward)} | Acc];
                                    Lv >= MinLv andalso Lv =< MaxLv andalso Score >= MinScore andalso Score =< MaxScore ->
                                        [{GradeId, Type, MinScore, MaxScore, util:term_to_string(Reward)} | Acc];
                                    true -> Acc
                                end;
                            _ ->
                                ?ERR("data_reversi config error SubType = ~p, GradeId = ~p", [SubType, GradeId]),
                                Acc
                        end
                        end,
                    GradeIds = data_reversi:get_grade_list(SubType),
                    PackReward = lists:foldl(F, [], GradeIds),
                    lib_server_send:send_to_sid(Sid, pt_332, 33266, [?SUCCESS, SubType, Score, FreeTimes, util:term_to_string(Cost), PackReward])
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

%% 抽奖所需价格
lottery_cost(Condition) ->
    CostList = data_reversi:get_value(consume_type),
    case lists:keyfind(consume_type, 1, Condition) of
        {_, Type} ->
            case lists:keyfind(Type, 1, CostList) of
                {_, Cost} -> Cost;
                _ -> false
            end;
        _ -> false
    end.

%% 活动状态
get_act_status(SubType, RoleId, RoleLv) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_REVERSI, SubType) of
        #act_info{key = {_, SubType}} ->
            case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_REVERSI, SubType) of
                #custom_act_cfg{condition = Condition} ->
                    case lists:keyfind(role_lv, 1, Condition) of
                        {_, Lv} when RoleLv >= Lv ->
                            #custom_act_data{
                                act_data = ActData
                            } = CustomData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_REVERSI, SubType),
                            NewData =
                                if
                                    ActData =:= [] ->
                                        init_act_data(SubType, RoleLv);
                                    true ->
                                        ActData
                                end,
                            if
                                NewData =:= false ->
                                    {false, ?MISSING_CONFIG};
                                NewData =/= ActData ->
                                    NewCustomData = CustomData#custom_act_data{act_data = NewData},
                                    lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
                                    {Condition, NewCustomData, NewData};
                                true ->
                                    {Condition, CustomData, NewData}
                            end;
                        _ -> {false, ?ERRCODE(lv_limit)}
                    end;
                _ ->
                    {false, ?MISSING_CONFIG}
            end;
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end.

%% 获取奖池信息
get_lottery_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_act_status(SubType, RoleId, Lv) of
        {_Condition, _CustomData, ActData} ->
            #reversi_data{pool_info = PoolInfo} = ActData,
            PoolList = [begin
                            if
                                Status =:= 1 ->
                                    #reversi_reward{reward = Reward} = data_reversi:get_reward_info(SubType, Grade),
                                    [{_, GoodsId, GoodsNum} | _] = Reward,
                                    {GridNum, Status, GoodsId, GoodsNum};
                                true ->
                                    {GridNum, Status, 0, 0}
                            end
                        end
                || {GridNum, Grade, Status} <- PoolInfo],
            lib_server_send:send_to_sid(Sid, pt_332, 33268, [?SUCCESS, SubType, PoolList]);
        {false, ErrCode} ->
            {false, ErrCode}
    end.

%% 展示的小奖池信息
get_display_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_act_status(SubType, RoleId, Lv) of
        {_Condition, _CustomData, ActData} ->
            #reversi_data{score = Score, pool_info = PoolInfo, grade_order = GradeOrder} = ActData,
            GradeList = [Grade || {_, Grade, Status} <- PoolInfo, Status =:= 1],
            PoolList = [begin
                            #reversi_reward{type = Type, reward = Reward} = data_reversi:get_reward_info(SubType, Grade),
                            [{_, GoodsId, GoodsNum} | _] = Reward,
                            {Type, Grade, GoodsId, GoodsNum}
                        end
                || Grade <- urand:list_shuffle(GradeList ++ GradeOrder)],
            case get_refresh_price() of
                {false, ErrorCode} ->
                    {false, ErrorCode};
                {Cost, Cost2} ->
                    lib_server_send:send_to_sid(Sid, pt_332, 33269,
                        [?SUCCESS, SubType, Score, util:term_to_string(Cost), util:term_to_string(Cost2), PoolList])
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

%% 刷新奖池价格
get_refresh_price() ->
    case data_reversi:get_value(fresh) of
        [{GoodType, GoodId, Num1} | _] = Cost1 ->
            case data_reversi:get_value(fresh_extra) of
                [{GoodType, GoodId, Num2} | _] = Cost2 when Num2 > Num1 -> {Cost1, Cost2};
                [] -> {false, ?ERRCODE(missing_config)}
            end;
        _ -> {false, ?ERRCODE(missing_config)}
    end.

%% 刷新奖池
refresh_pool(Player, SubType, IsLucky) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_act_status(SubType, RoleId, Lv) of
        {Condition, CustomData, ActData} ->
            #reversi_data{pool_info = PoolInfo} = ActData,
            Predicate = fun({_, _, Status}) -> Status =:= 0 end,
            IsCost = lists:any(Predicate, PoolInfo),
            {Cost1, Cost2} = get_refresh_price(),
            %% 勾选幸运大奖必然多得一个幸运大奖
            {Cost, ExtraCount} =
                if
                    IsCost andalso IsLucky =:= 0 -> %% 当前奖池还没全部翻开且勾选幸运大奖
                        {Cost1, 0};
                    IsCost andalso IsLucky =:= 1 ->
                        {Cost2, 1};
                    IsLucky =:= 1 -> %% 当前奖池全部翻开且勾选幸运大奖
                        [{GoodType, GoodId, Num1} | _] = Cost1,
                        [{GoodType, GoodId, Num2} | _] = Cost2,
                        {[{GoodType, GoodId, Num2 - Num1}], 1};
                    true -> {[], 0}
                end,
            RealCost =
                if
                    Cost =:= [] -> [];
                    true ->
                        [{_, CostGId, Num} | _] = Cost,
                        [{_, OwnNum} | _] = lib_goods_api:get_goods_num(Player, [CostGId]),
                        calc_price_cost(CostGId, Num, OwnNum)
                end,
            case do_refresh_pool(Player, SubType, Lv, Condition, CustomData, ActData, RealCost, ExtraCount) of
                {true, NewPlayer} ->
                    {true, NewPlayer};
                {false, Err} ->
                    {false, Err}
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

do_refresh_pool(Player, SubType, Lv, Condition, CustomData, ActData, Cost, ExtraCount) ->
    #reversi_data{score = Score, limit_grades = LimitGrades, free_times = FreeTimes} = ActData,
    #player_status{id = RoleId, sid = Sid, gold = Gold, bgold = Bgold} = Player,
    case lists:keyfind(pool_type, 1, Condition) of
        {_, RuleList} ->
            ActData0 = init_act_pool(SubType, Lv, Score + 1, RuleList, LimitGrades, ExtraCount),
            if
                is_record(ActData0, reversi_data) ->
                    case lib_goods_api:cost_object_list_with_check(Player, Cost, reversi_lottery, "") of
                        {true, NewPlayer, _} ->
                            NewActData = ActData0#reversi_data{score = Score + 1, limit_grades = LimitGrades, free_times = FreeTimes},
                            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
                            lib_custom_act_data:save_custom_data(Player#player_status.id, NewCustomData),
                            #reversi_data{grade_order = GradeOrder} = NewActData,
                            PoolList = [begin
                                            #reversi_reward{type = Type, reward = Reward} = data_reversi:get_reward_info(SubType, Grade),
                                            [{_, GoodsId, GoodsNum} | _] = Reward,
                                            {Type, Grade, GoodsId, GoodsNum}
                                        end
                                || Grade <- urand:list_shuffle(GradeOrder)],
                            lib_log_api:log_reversi_lottery([RoleId, ?CUSTOM_ACT_TYPE_REVERSI, SubType, 2, Score, util:term_to_bitstring([]), utime:unixtime(),
                                Gold, NewPlayer#player_status.gold, Bgold, NewPlayer#player_status.bgold]),
                            lib_server_send:send_to_sid(Sid, pt_332, 33270, [?SUCCESS, SubType, Score + 1, PoolList]),
                            {true, NewPlayer};
                        {false, Err, _} ->
                            {false, Err}
                    end;
                true ->
                    {false, ?ERRCODE(missing_config)}
            end;
        _ ->
            {false, ?ERRCODE(missing_config)}
    end.

%%道具消耗逻辑
calc_price_cost(CostGId, NeedNum, OwnNum) ->
    case data_goods:get_goods_buy_price(CostGId) of
        {0, 0} ->
            [{?TYPE_GOODS, CostGId, NeedNum}];%%没有道具配置的话  让扣道具报道具不足
        {PriceType, Price} ->
            NeedBuy = case OwnNum >= NeedNum of
                          true ->
                              0;
                          _ ->
                              max(NeedNum - OwnNum, 1)
                      end,
            case NeedBuy =< 0 of
                true -> %%不需要购买
                    [{?TYPE_GOODS, CostGId, NeedNum}];
                false ->
                    case OwnNum =< 0 of
                        true ->
                            [{PriceType, 0, Price * NeedBuy}];
                        _ ->
                            [{?TYPE_GOODS, CostGId, OwnNum}, {PriceType, 0, Price * NeedBuy}]
                    end
            end
    end.

%% 抽奖
lottery(Player, SubType) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    #figure{lv = Lv} = Figure,
    case get_act_status(SubType, RoleId, Lv) of
        {Condition, CustomData, ActData} ->
            PoolInfo = ActData#reversi_data.pool_info,
            Predicate = fun({_, _, Status}) -> Status =:= 0 end,
            IsLottery = lists:any(Predicate, PoolInfo),
            case lottery_cost(Condition) of
                false ->
                    {false, ?ERRCODE(missing_config)};
                CostList when IsLottery ->
                    do_lottery(Player, SubType, CustomData, ActData, CostList);
                _ ->
                    {false, ?ERRCODE(err331_refresh_pool)}
            end;
        {false, ErrCode} ->
            {false, ErrCode}
    end.

do_lottery(Player, SubType, CustomData, ActData, CostList) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure, gold = Gold, bgold = Bgold} = Player,
    #figure{name = Name} = Figure,
    #reversi_data{pool_info = PoolInfo, grade_order = GradeOrder, score = Score, limit_grades = LimitGrades, free_times = FreeTimes, route = RouteList} = ActData,
%% 其它折扣活动对于抽奖可打折，由于换成了道具抽奖，且道具数量为1，因此先屏蔽，有需要再加回来
    DisT0 = calc_dis_type(Player),
    {NewFreeTimes, Cost} =
        case DisT0 of
            activity_free->
                custom_unite_buff:cost_times(Player, activity_free, ?CUSTOM_ACT_TYPE_REVERSI),
                {FreeTimes, []};
            _ when FreeTimes>0 ->
                {FreeTimes - 1, []};
            _->
                {FreeTimes, CostList}
        end,
    case lib_goods_api:cost_objects_with_auto_buy(Player, Cost, reversi_lottery, "") of
        {true, Player1, _} ->
            {LatticeNum, NewRoute} = get_lattice_and_route(RouteList, PoolInfo),
            ObList = lib_reversi:get_passive_lattice(PoolInfo, LatticeNum),
            %% 更新数据
            F = fun(Number, {Pool, TempGrades, [Grade | L], ObGrade}) ->
                NewPool = lists:keystore(Number, 1, Pool, {Number, Grade, 1}),
                NewTempGrades =
                    case lists:keyfind(Grade, 1, TempGrades) of
                        {_, Times} -> lists:keystore(Grade, 1, TempGrades, {Grade, Times + 1});
                        _ -> lists:keystore(Grade, 1, TempGrades, {Grade, 1})
                    end,
                {NewPool, NewTempGrades, L, [{Number, Grade} | ObGrade]}
                end,
            {NewPoolInfo, NewLimitGrades, NewGradeOrder, Obtain} = lists:foldl(F, {PoolInfo, LimitGrades, GradeOrder, []}, [LatticeNum | ObList]),
            %% 由获得的奖励Id得到奖励列表、能触发传闻的列表、发给客户端的数据
            F2 = fun({Number, Grade}, {Rewards, Tv, Acc}) ->
                case data_reversi:get_reward_info(SubType, Grade) of
                    #reversi_reward{reward = [{_GoodType, GoodId, GoodNum} | _] = Reward, is_lucky = IsLucky, is_tv = IsTv} when IsTv =:= 1 ->
                        {Reward ++ Rewards, [GoodId | Tv], [{Number, IsLucky, GoodId, GoodNum} | Acc]};
                    #reversi_reward{reward = [{_GoodType, GoodId, GoodNum} | _] = Reward, is_lucky = IsLucky} ->
                        {Reward ++ Rewards, Tv, [{Number, IsLucky, GoodId, GoodNum} | Acc]};
                    _ -> {Rewards, Tv, Acc}
                end
                 end,
            {RewardList, TvList, PackList} = lists:foldl(F2, {[], [], []}, Obtain),
            [lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 36, [Name, Score, GoodsId]) || GoodsId <- TvList],
            NewActData = ActData#reversi_data{pool_info = NewPoolInfo, grade_order = NewGradeOrder, limit_grades = NewLimitGrades, free_times = NewFreeTimes, route = NewRoute},
            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
            % 背包容量不足发邮件
            Produce = #produce{title = utext:get(33111501), content = utext:get(33111502), reward = RewardList, type = reversi_drop},
            {ok, Player2} = lib_goods_api:send_reward_with_mail(Player1, Produce),
            lib_log_api:log_reversi_lottery([RoleId, ?CUSTOM_ACT_TYPE_REVERSI, SubType, 1, Score, util:term_to_bitstring(RewardList),
                utime:unixtime(), Gold, Player2#player_status.gold, Bgold, Player2#player_status.bgold]),
            lib_server_send:send_to_sid(Sid, pt_332, 33267, [?SUCCESS, SubType, NewFreeTimes, util:term_to_string(CostList), PackList]),
            {true, Player2};
        {false, Err, _} ->
            {false, Err}
    end.

%% 获取将要翻开的格子编号和剩余路线
get_lattice_and_route(RouteList, PoolInfo) ->
    case RouteList of
        [Lattice | T] ->
            case lists:keyfind(Lattice, 1, PoolInfo) of
                {Lattice, _, 0} ->
                    {Lattice, T};
                _ ->
                    get_lattice_and_route(T, PoolInfo)
            end;
        _ ->
            Lattice = get_lattice_num(PoolInfo),
            {Lattice, []}
    end.

%% 获取还未翻开的格子编号
get_lattice_num([{LatticeNum, _Grade, Status} | T]) ->
    if
        Status =:= 0 -> LatticeNum;
        true -> get_lattice_num(T)
    end.

%% 初始化数据
init_act_data(SubType, Lv) ->
    case lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_REVERSI, SubType) of
        #custom_act_cfg{condition = Condition} -> skip;
        _ -> Condition = []
    end,
    case lists:keyfind(pool_type, 1, Condition) of
        {_, RuleList} ->
            case data_reversi:get_value(init_lucky) of
                [InitScore] ->
                    ActData = init_act_pool(SubType, Lv, InitScore, RuleList, [], 0),
                    ActData;
                _ -> false
            end;
        _ -> false
    end.

%% LimitGrades: 活动期间，已达最大获取次数的grade
%% RuleList: 规则列表（[{type,x}]）从类型为type的奖励中挑选x个
%% ExtraCount: 玩家勾选幸运大奖刷新奖池时，type为1的奖励需要多增加一个
init_act_pool(SubType, Lv, Score, RuleList, LimitGrades, ExtraCount) ->
    {MaxType, _} = ulists:keymax(1, RuleList),
    F = fun({Type, Count}, {ChangeCount, PoolList, SpecialList}) ->
        GradeIds = data_reversi:get_grade_for_type(SubType, Type),
        FilterGrades = filter_grade(SubType, Lv, Score, GradeIds, [], LimitGrades),
        Times =
            if
                Type =:= 1 -> Count + ChangeCount;
                Type =:= MaxType -> Count - ChangeCount;
                true -> Count
            end,
        RandGrades = get_rand_grades(SubType, FilterGrades, [], Times),
        % ReqLimit：此奖励从第几格开始才能被抽到，与运营约定为1时无要求
        {Pool, List} =
            lists:foldl(fun
                            ({Grade, Total, ReqLimit}, {List, List2}) when ReqLimit =:= 1 andalso Total =:= 1 ->
                                {[Grade | List], List2};
                            ({Grade, Total, ReqLimit}, {List, List2}) when ReqLimit =:= 1 ->
                                Grades = lists:duplicate(Total, Grade),
                                {Grades ++ List, List2};
                            ({Grade, Total, ReqLimit}, {List, List2}) ->
                                {List, [{ReqLimit, Grade, Total} | List2]}
                        end, {[], []}, RandGrades),
        {ChangeCount, Pool ++ PoolList, List ++ SpecialList}
        end,
    {_, PoolList, SpecialList0} = lists:foldl(F, {ExtraCount, [], []}, RuleList),
    Length0 = length(PoolList),
    Length = length(SpecialList0),
    LeftNum = 16 - (Length0 + Length),
    RealPoolList =
        if
            LeftNum > 0 -> % 配置有点问题，为了容错所以从取最低档奖励补上
                {_, PoolList0, _} = lists:foldl(F, {0, [], []}, [{MaxType, LeftNum}]),
                PoolList0 ++ PoolList;
            true ->
                PoolList
        end,

    % 打乱列表以此做到随机
    ShuffleList0 = urand:list_shuffle(RealPoolList),
    % 将有特殊规则的奖励做特殊处理，得到它们的位置
    LatticeList = special_sort(SpecialList0),
    SeqLists = lists:seq(1, ?LATTICE_NUM),
    PoolInfo = [{LatticeNum, 0, 0} || LatticeNum <- SeqLists],
    F2 = fun(LatticeNum, {ShuffleList, SpecialList, RealPool}) ->
        case lists:keyfind(LatticeNum, 1, SpecialList) of
            false when ShuffleList == [] ->
                {ShuffleList, SpecialList, RealPool};
            false ->
                [Grade | L] = ShuffleList,
                {L, SpecialList, [Grade | RealPool]};
            {LatticeNum, Grade} -> {ShuffleList, SpecialList, [Grade | RealPool]}
        end
         end,
    {_, _, GradeOrder} = lists:foldl(F2, {ShuffleList0, LatticeList, []}, SeqLists),
    RouteId = get_rand_route(Score),
    #reversi_route{route_step = Route} = data_reversi:get_reversi_route(RouteId),
    GradeLen = length(GradeOrder),
    if
        GradeLen == ?LATTICE_NUM ->
            #reversi_data{pool_info = PoolInfo, grade_order = lists:reverse(GradeOrder), score = Score, route = Route};
        true ->
            ?ERR("Cfg error {LatticeList ShuffleList0} ~p~nGradeOrder length error  ~p",
                [{util:term_to_string(LatticeList), util:term_to_string(ShuffleList0)}, util:term_to_string(GradeOrder)]),
            false
    end.


%% 筛选符合条件的GradeId
filter_grade(_SubType, _Lv, _Score, [], GradeIds, _LimitGrades) ->
    GradeIds;
filter_grade(SubType, Lv, Score, [Grade | T], GradeIds, LimitGrades) ->
    case data_reversi:get_reward_info(SubType, Grade) of
        #reversi_reward{
            weight = Weight,
            limit = Limit,
            total_limit = TotalLimit,
            req_limit = ReqLimit,
            lucky = [MinScore, MaxScore],
            role_lv = [MinLv, MaxLv]
        } when Lv >= MinLv andalso Lv =< MaxLv andalso Score >= MinScore andalso Score =< MaxScore ->
            case lists:keyfind(Grade, 1, LimitGrades) of
                {_, Times} when Times >= TotalLimit ->
                    filter_grade(SubType, Lv, Score, T, GradeIds, LimitGrades);
                _ ->
                    filter_grade(SubType, Lv, Score, T, [{Weight, {Grade, Limit, ReqLimit}} | GradeIds], LimitGrades)
            end;
        _ ->
            filter_grade(SubType, Lv, Score, T, GradeIds, LimitGrades)
    end.

%% 从FilterGrades随机得到Count个奖励组成的列表[{GradeId, 出现次数, 最少抽几次才可能获得}]
get_rand_grades(_, [], RandGrades, _) ->
    RandGrades;
get_rand_grades(_SubType, _FilterGrades, RandGrades, 0) ->
    RandGrades;
get_rand_grades(SubType, FilterGrades, RandGrades, Count) ->
    {Grade, Limit, ReqLimit} = urand:rand_with_weight(FilterGrades),
    case lists:keyfind(Grade, 1, RandGrades) of
        {_, Times} when Times >= Limit -> % 已达到一轮奖池里最高出现次数
            #reversi_reward{weight = Weight} = data_reversi:get_reward_info(SubType, Grade),
            NewFilterGrades = lists:delete({Weight, {Grade, Limit, ReqLimit}}, FilterGrades),
            get_rand_grades(SubType, NewFilterGrades, RandGrades, Count);
        {_, Times} ->
            NewRandGrades = lists:keystore(Grade, 1, RandGrades, {Grade, Times + 1, ReqLimit}),
            get_rand_grades(SubType, FilterGrades, NewRandGrades, Count - 1);
        _ ->
            get_rand_grades(SubType, FilterGrades, [{Grade, 1, ReqLimit} | RandGrades], Count - 1)
    end.

%% 这类奖励只有在翻开一定格子数时才可能被抽到
%% 先对格子数进行排序，然后在[格子数-16]之间随机得到位置
special_sort(SpecialList) ->
    ShuffleList = urand:list_shuffle(SpecialList),
    SortFun = fun({ReqLimit1, _, _}, {ReqLimit2, _, _}) ->
        ReqLimit1 > ReqLimit2
              end,
    SortList = lists:sort(SortFun, ShuffleList),
    special_sort(SortList, [], []).
special_sort([], SpecialList, _) ->
    SpecialList;
special_sort([{ReqLimit, Grade, Times} | L], SpecialList, LatticeList) ->
    SeqList = lists:seq(ReqLimit, 16),
    RandList = urand:get_rand_list(Times, SeqList -- LatticeList),
    GradeList = [{LatticeNum, Grade} || LatticeNum <- RandList],
    special_sort(L, SpecialList ++ GradeList, RandList ++ LatticeList).

%% 随机得到route_id
get_rand_route(Score) ->
    RouteList = data_reversi:get_route_list(),
    WeightList =
        [begin
             #reversi_route{
                 weight = Weight,    %% 路线权重
                 weight_temp = WeightTemp,   %% 临时权重
                 temp_lowlimit = LowLimit,   %% 临时权重下限
                 temp_toplimit = TopLimit    %% 临时权重上限
             } = data_reversi:get_reversi_route(RouteId),
             if
                 Score >= LowLimit, Score =< TopLimit ->
                     {Weight + WeightTemp, RouteId};
                 true ->
                     {Weight, RouteId}
             end
         end || RouteId <- RouteList],
    urand:rand_with_weight(WeightList).


%% ---------------gm-------------------
%% 指定路线
gm_reset_route(Player, SubType, RouteId) ->
    #player_status{sid = Sid, id = RoleId, figure = Figure} = Player,
    Lv = Figure#figure.lv,
    case get_act_status(SubType, RoleId, Lv) of
        {Condition, CustomData, ActData} ->
            case do_refresh_pool(Player, SubType, Lv, Condition, CustomData, ActData, [], 0) of
                {true, _NewPlayer} ->
                    #custom_act_data{
                        act_data = ActData2
                    } = CustomData2 = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_REVERSI, SubType),
                    #reversi_data{score = Score, grade_order = GradeOrder} = ActData2,
                    #reversi_route{route_step = Route} = data_reversi:get_reversi_route(RouteId),
                    NewData = ActData2#reversi_data{route = Route, score = Score - 1},
                    NewCustomData = CustomData2#custom_act_data{act_data = NewData},
                    lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
                    PoolList = [begin
                                    #reversi_reward{type = Type, reward = Reward} = data_reversi:get_reward_info(SubType, Grade),
                                    [{_, GoodsId, GoodsNum} | _] = Reward,
                                    {Type, Grade, GoodsId, GoodsNum}
                                end
                        || Grade <- urand:list_shuffle(GradeOrder)],
                    lib_server_send:send_to_sid(Sid, pt_332, 33270, [?SUCCESS, SubType, Score - 1, PoolList]);
                {false, Err} ->
                    {false, Err}
            end;
        _ -> skip
    end.

%% 校验所有路线是否正确
gm_check_route() ->
    AllRoute = data_reversi:get_route_list(),
    SeqList = lists:seq(1, 16),
    PoolInfo = [{Num, 0, 0} || Num <- SeqList],
    Predicate = fun({_, _, State}) -> State =:= 1 end,
    [begin
         #reversi_route{route_step = RouteList} = data_reversi:get_reversi_route(RouteId),
         F = fun(LatticeNum, PoolInfo1) ->
             LatticeList = lib_reversi:get_passive_lattice(PoolInfo1, LatticeNum),
             F2 = fun(Number, PoolInfo2) ->
                 lists:keystore(Number, 1, PoolInfo2, {Number, 0, 1})
                  end,
             lists:foldl(F2, PoolInfo1, [LatticeNum | LatticeList])
             end,
         NewPoolInfo = lists:foldl(F, PoolInfo, RouteList),
         {RouteId, lists:all(Predicate, NewPoolInfo)}
     end || RouteId <- AllRoute].

%% 重置数据
gm_reset_data(Player, SubType) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    Lv = Figure#figure.lv,
    CustomData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_REVERSI, SubType),
    NewCustomData = CustomData#custom_act_data{act_data = []},
    lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
    get_act_status(RoleId, Lv, SubType).

%%折扣类型计算
%%先看有没有免费
%%再看看有没有折扣
calc_dis_type(Player) ->
    UniteNumFree = custom_unite_buff:check_times(Player, activity_free, ?CUSTOM_ACT_TYPE_REVERSI),
    case UniteNumFree > 0 of
        true ->
            activity_free; %%免费
        _ ->
%%            UniteNumDis = custom_unite_buff:check_times(Player,activity_discount,?CUSTOM_ACT_TYPE_REVERSI),
%%            case UniteNumDis>0 of
%%                true->
%%                    activity_discount;
%%                _->
%%                    0
%%            end
            0
    end.