%%% ----------------------------------------------------
%%% @Module:        mod_3v3_pk
%%% @Author:        zhl
%%% @Description:   跨服3v3战斗房间
%%% @Created:       2017/07/07
%%% ----------------------------------------------------

-module(mod_3v3_pk).
-behaviour(gen_server).

-export([
        init/1,
        handle_call/3,
        handle_cast/2,
        handle_info/2,
        terminate/2,
        code_change/3
    ]).

-export([
        start/1,                                %% 启动3v3战斗进程
        start_fight/0,                          %% 开始战斗
        stop_fight/0,                           %% 结束战斗

        create_mons/1,                          %% 创建房间怪物
        to_team_score/1,                        %% 转换#team_score{}
        kick_out_room/1,                        %% 将房间内所有玩家踢出场景
        tower_be_collected/5,                   %% 塔被占领
        buff_be_collected/5,                    %% buff采集完毕
        test/0
    ]).

-include("predefine.hrl").
-include("scene.hrl").
-include("battle.hrl").
-include("common.hrl").
-include("chat.hrl").
-include("3v3.hrl").
-include("errcode.hrl").
-include("figure.hrl").
-include("def_module.hrl").

%% ================== 3v3游戏部分规则=======================
%%
%% 占据塔数，积分（个人积分，队伍总积分）
%% 神塔每5s + 5积分
%% 击杀1人 + 2积分
%% 复活3s
%% 无敌10s
%%
%% ================== 3v3游戏部分规则=======================

%% @desc : 不能让子进程挂掉而导致公共进程挂掉
start(Args) ->
    gen_server:start(?MODULE, Args, []).

start_fight() ->
    self() ! {start_fight}.

stop_fight() ->
    self() ! {stop_fight}.


test() -> ok.

init([PKData]) ->
    #kf_3v3_pk_data{
        scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID, team_data_a = TeamA, team_data_b = TeamB
    } = PKData,
    send_power_contrast(TeamA, TeamB), %% 发送双方的战力对比
    erlang:send_after(3000, self(), {pk_start}), %% 三秒之后拉人进房间战斗
    {TeamList, RoleList} = to_team_score([TeamA, TeamB]),
    State = #center_pk_state{
        scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID, pk_state = ?KF_3V3_PK_READY, team_score = TeamList,
        role_score = RoleList, ed_time = utime:unixtime() + ?KF_3V3_PK_TIME + 3
    },
    {ok, State}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(_Request, State) ->
    {noreply, State}.

handle_info(Request, State) ->
    try
        do_handle_info(Request, State)
    catch
        throw:{error, _Reason} ->
            {noreply, State};
        throw:_ ->
            {noreply, State};
        _:Error ->
            ?ERR("handle call exception~n"
                 "error:~p~n"
                 "state:~p~n"
                 "stack:~p", [Error, State, erlang:get_stacktrace()]),
            {noreply, State}
    end.

terminate(
        _Reason
        , #center_pk_state{
            scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID,
            team_score = _TeamList, role_score = RoleList
            }
        ) ->
    leave_team(RoleList), %% 战斗结束

    % UserList = lib_scene:get_scene_user(SceneID, RoomID),
    % kick_out_room(UserList), %% 将房间内所有玩家踢出房间
    % lib_mon:clear_scene_mon(SceneID, RoomID, 1), %% 清除房间怪物
    %% 将房间内所有玩家踢出房间
    case mod_scene_agent:apply_call(SceneID, ScenePoolId, lib_scene_agent, get_scene_user, [RoomID]) of
        false -> skip;
        UserList -> kick_out_room([UserList, RoleList])
    end,
    %% 清除房间数据
    lib_scene:clear_scene_room(SceneID, ScenePoolId, RoomID),

    % io:format("----UserList---~p~n", [UserList]),
    mod_3v3_center:stop_pk_room([SceneID, RoomID]), %% 退出房间 - 最好放在最后执行这方法
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%% 发出开始战斗信号 - 拉人进场景
do_handle_info({pk_start}, State) ->
    erlang:send_after(?KF_3V3_PK_TIME * 1000, self(), {stop_fight}), %% 三分钟之后终止，避免一直占用房间
    erlang:send_after(?KF_3V3_CREATE_BUFF_TIME * 1000, self(), {create_buff}), %% 两分钟之后刷出buff
    #center_pk_state{
        scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID, role_score = RoleList
    } = State,
    TowerData = create_mons([SceneID, ScenePoolId, RoomID]), %% 生成房间怪物
    pull_into_room(RoleList, [SceneID, ScenePoolId, RoomID]), %% 拉人进场景
    {noreply, State#center_pk_state{pk_state = ?KF_3V3_PK_START, tower_data = TowerData}};

%% 终止战斗
do_handle_info({stop_fight}, #center_pk_state{scene_id = SceneID,  scene_pool_id = ScenePoolId, room_id = RoomID,
    team_score = TeamList, tower_data = TowerData, role_score = RoleList, timer = Timer, ed_time = EdTime} = State)
    when EdTime > 0 ->
    util:cancel_timer(Timer),
    erlang:send_after(10000, self(), {stop_pk_room}), %% 10s之后无论如何都会将玩家踢出场景
    mod_3v3_center:update_team_pk([[TeamId||#team_score{team_id =TeamId}<-TeamList], 0]),
    % UserList = lib_scene:get_scene_user(SceneID, RoomID),
    case mod_scene_agent:apply_call(SceneID, ScenePoolId, lib_scene_agent, get_scene_user, [RoomID]) of
        false -> UserList = [];
        UserList -> ok
    end,
    lib_mon:clear_scene_mon(SceneID, ScenePoolId, self(), 1),   %% 清除房间怪物
    RoleList1 = reset_online_all(RoleList, UserList), %% 活动结束就获取玩家是否在线
    {Data, NRoleList} = calc_result_room(TeamList, TowerData, RoleList1), %% 结算积分，胜负
    log(State, Data, NRoleList),
    send_pk_result(NRoleList, Data), %% 推送战斗结算
    refresh_3v3_rank(NRoleList), %% 刷新积分排行榜
    {noreply, State#center_pk_state{role_score = NRoleList, ed_time = 0}};

%% 打扫房间
do_handle_info({stop_pk_room}, State) ->
    {stop, normal, State};

%% 水晶塔采集完毕
do_handle_info(
        {tower_collect_complete, [SceneId, ScenePoolId, RoomID, RoleID, MonID]}
        , #center_pk_state{
            team_score = TeamList, tower_data = TowerData,
            role_score = RoleList, timer = Timer, ed_time = EdTime
        } = State) when EdTime > 0 ->
    #role_score{group = Group, figure = #figure{
        name = Nickname, career = Career, turn = Turn, picture = Picture, picture_ver = PictureVer}
        }= lists:keyfind(RoleID, #role_score.role_id, RoleList),
    if
        Timer == [] -> %% 每5s增加一次队伍积分
            NTimer = erlang:send_after(5000, self(), {tower_score});
        true -> NTimer = Timer
    end,
    case data_mon:get(MonID) of
        #mon{type = Type, name = MonName} ->
            % case Group == ?KF_3V3_GROUP_RED of
            %     true -> GroupName = utext:get(324);
            %     false -> GroupName  = utext:get(325)
            % end,
            % 编码可能有问题,用进程发送
            {ok, BinData} = pt_650:write(65043, [1, MonID, RoleID, Nickname, Career, Turn, Picture, PictureVer]),
            spawn(fun() ->
                lib_server_send:send_to_scene(SceneId, ScenePoolId, RoomID, BinData),
                lib_chat:send_TV({scene, SceneId, ScenePoolId, RoomID}, ?MOD_KF_3V3, 1, [MonName, unicode:characters_to_list(Nickname,unicode)])
            end),
            NMonID = lib_3v3_center:get_tower_id(Group, MonID),
            {X, Y} = lib_3v3_center:get_tower_xy(MonID),
            CollectHandler = {?MODULE, tower_be_collected, self()},
            lib_mon:async_create_mon(NMonID, SceneId, ScenePoolId, X, Y, Type, RoomID, 1, [{group, Group},{collected_handler, CollectHandler}]);
        _ -> skip
    end,
    NTeamList = add_score_team(TeamList, [Group, 2]), %% 队伍积分变动
    NRoleList = add_score_role(State, RoleList, RoleID, [{collect, 1}]), %% 玩家积分变动
    NTowerData = occupy_tower(TowerData, MonID, Group), %% 神塔变动
    % io:format("--------collect_complete-------~n"),
    send_occupy_tower(NRoleList), %% 推送神塔采集广播
    send_score_notice(NTeamList, NRoleList), %% 推送积分变更广播
    {noreply, State#center_pk_state{team_score = NTeamList, role_score = NRoleList,
        tower_data = NTowerData, timer = NTimer}};

%% buff采集完毕
do_handle_info(
        {buff_collect_complete, [SceneId, ScenePoolId, RoomID, _Node, RoleID, MonID, SkillId, SkillLv]}
        , #center_pk_state{role_score = RoleList, ed_time = EdTime} = State) when EdTime > 0 ->
    #role_score{figure = #figure{name = Nickname, career = Career, turn = Turn, picture = Picture, picture_ver = PictureVer}
        }= lists:keyfind(RoleID, #role_score.role_id, RoleList),
    lib_battle_api:assist_anything(SceneId, ScenePoolId, ?BATTLE_SIGN_PLAYER, RoleID, ?BATTLE_SIGN_PLAYER, RoleID, SkillId, SkillLv),
    % CastArgs = [RoleID, ?APPLY_CAST_SAVE, lib_goods_buff, add_skill_buff, [SkillId, SkillLv] ],
    % clusters_center:apply_cast(Node, lib_player, apply_cast, CastArgs),
    MonName = get_mon_name(MonID),
    % 编码可能有问题,用进程发送
    {ok, BinData} = pt_650:write(65043, [2, MonID, RoleID, Nickname, Career, Turn, Picture, PictureVer]),
    spawn(fun() ->
        lib_server_send:send_to_scene(SceneId, ScenePoolId, RoomID, BinData),
        lib_chat:send_TV({scene, SceneId, ScenePoolId, RoomID}, ?MOD_KF_3V3, 5,
            [MonName, unicode:characters_to_list(Nickname, unicode)]) end),
    {noreply, State};

%% 击杀玩家
do_handle_info({kill_enemy, DefRoleID, AtterSign, AttRoleID},
    #center_pk_state{team_score = TeamList, role_score = RoleList, scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID,
    ed_time = EdTime} = State) when EdTime > 0 ->
    if
        AtterSign == ?BATTLE_SIGN_PLAYER ->
            case lists:keyfind(AttRoleID, #role_score.role_id, RoleList) of
                #role_score{figure = AttFigure, group = Group} ->
                    #figure{name = AttName, career = AttCareer, turn = AttTurn, picture = AttPicture, picture_ver = AttPictureVer} = AttFigure,
                    case lists:keyfind(DefRoleID, #role_score.role_id, RoleList) of
                        #role_score{figure = DefFigure} ->
                            #figure{name = DefName, career = DefCareer, turn = DefTurn, picture = DefPicture, picture_ver = DefPictureVer} = DefFigure,
                            {ok, BinData} = pt_650:write(65042, [AttRoleID, AttName, AttCareer, AttTurn, AttPicture, AttPictureVer,
                                    DefRoleID, DefName, DefCareer, DefTurn, DefPicture, DefPictureVer]),
                            % 编码可能有问题,用进程发送
                            spawn(fun() ->
                                lib_server_send:send_to_scene(SceneID, ScenePoolId, RoomID, BinData),
                                lib_chat:send_TV({scene, SceneID, ScenePoolId, RoomID}, ?MOD_KF_3V3, 2, [AttName, DefName])
                            end);
                        _ ->
                            skip
                    end,
                    NTeamList = add_score_team(TeamList, [Group, 2]), %% 积分变动
                    RoleList1 = add_score_role(State, RoleList, AttRoleID, [{kill, 1}, {continued_kill, 1}]),
                    NRoleList = add_score_role(State, RoleList1, DefRoleID, [{killed, 1}, {continued_kill, 0}]);
                _ ->
                    NTeamList = TeamList,
                    NRoleList = RoleList
            end;
        true ->
            NTeamList = TeamList,
            NRoleList = add_score_role(State, RoleList, DefRoleID, [{killed, 1}, {continued_kill, 0}])
    end,
    % io:format("-------kill_enemy------~p~n", [{DefRoleID, AttRoleID, NRoleList}]),
    send_score_notice(NTeamList, NRoleList), %% 推送积分变更广播
    {noreply, State#center_pk_state{team_score = NTeamList, role_score = NRoleList}};

%% 每5s增加一次队伍积分
%% 占领塔后，每5秒每个塔提供队伍积分+2，一个塔如果被连续占领1分钟，此后每5秒该塔提供队伍积分+5
do_handle_info({tower_score}, #center_pk_state{team_score = TeamList, tower_data = TowerData,
    role_score = RoleList, ed_time = EdTime} = State) when EdTime > 0 ->
    Timer = erlang:send_after(5000, self(), {tower_score}),
    NowTime = utime:unixtime(),
    F = fun(#tower_data{time = Time, group = Group}, List) ->
        if
            NowTime >= Time + 40 -> add_score_team(List, [Group, 6]);
            true ->                 add_score_team(List, [Group, 3])
        end
    end,
    NTeamList = lists:foldl(F, TeamList, TowerData),
    send_score_notice(NTeamList, RoleList), %% 推送积分变更广播
    {noreply, State#center_pk_state{timer = Timer, team_score = NTeamList}};

%% 获取战场信息
do_handle_info({get_battle_info, [ServerId, RoleSid, TeamID]}, State) ->
    BattleInfo = to_battle_info(State, TeamID),
    clusters_center:apply_cast(ServerId, lib_3v3_local, send_battle_info, [[RoleSid, BattleInfo]]),
    {noreply, State};

%% 离开战斗房间
%% @desc : 战斗未结算不能主动退出战场，主动退出战场不退出队伍
do_handle_info({leave_pk_room, RoleID, Type}, #center_pk_state{
    role_score = RoleList, ed_time = EdTime} = State) ->
    case lists:keyfind(RoleID, #role_score.role_id, RoleList) of
        #role_score{
            server_id = ServerId, old_scene_info = OldScenInfo
        } = RoleScore when Type == ?PK_3V3_ONLINE andalso EdTime == 0 -> %% 结算时退出房间
            NRoleScore = RoleScore#role_score{online = Type},
            NRoleList = lists:keyreplace(
                RoleID, #role_score.role_id, RoleList, NRoleScore),
            NState = State#center_pk_state{role_score = NRoleList},
            kick_out_room([ServerId, RoleID, OldScenInfo]);
        #role_score{} = RoleScore when Type == ?PK_3V3_OFFLINE -> %% 掉线
            NRoleScore = RoleScore#role_score{online = Type},
            NRoleList = lists:keyreplace(
                RoleID, #role_score.role_id, RoleList, NRoleScore),
            NState = State#center_pk_state{role_score = NRoleList};
        _ ->
            NState = State
    end,
    {noreply, NState};

%% 重登战斗战场
do_handle_info({enter_pk_room, [RoleID, RoleSid]}, #center_pk_state{scene_id = SceneID, scene_pool_id = ScenePoolId,
    room_id = RoomID, role_score = RoleList, ed_time = EdTime} = State) ->
    NowTime = utime:unixtime(),
    if
        EdTime - NowTime =< 10 -> %% 玩家重登离战斗结束只剩10s，不拉进战场
            NRoleList = RoleList;
        true ->
            case lists:keyfind(RoleID, #role_score.role_id, RoleList) of
                #role_score{} = RoleScore ->
                    NRoleScore = RoleScore#role_score{sid = RoleSid, online = ?PK_3V3_ONLINE},
                    NRoleList = lists:keyreplace(
                        RoleID, #role_score.role_id, RoleList, NRoleScore);
                _ ->
                    NRoleList = RoleList
            end,
            enter_pk_room(NRoleList, [RoleID, SceneID, ScenePoolId, RoomID]) %% 把玩家重新拉进战场
    end,
    {noreply, State#center_pk_state{role_score = NRoleList}};

%% 退出队伍，并退出房间
do_handle_info({leave_team, RoleID}, #center_pk_state{ed_time = EdTime,
    role_score = RoleList} = State) ->
    RoleScore = lists:keyfind(RoleID, #role_score.role_id, RoleList),
    if
        EdTime == 0 andalso RoleScore /= false -> %% 战斗结束，可以退出队伍
            #role_score{server_id = ServerId, old_scene_info = OldScenInfo} = RoleScore,
            mod_3v3_center:ret_leave_team(RoleID),
            kick_out_room([ServerId, RoleID, OldScenInfo]),

            NRoleList = lists:keydelete(RoleID, #role_score.role_id, RoleList),
            NState = State#center_pk_state{role_score = NRoleList};
        RoleScore /= false -> %% 战斗未结束，不能退出队伍
            #role_score{server_id = ServerId, sid = _RoleSid} = RoleScore,
            clusters_center:apply_cast(ServerId, mod_3v3_local, send_leave_team, [[RoleID, ?ERRCODE(err650_kf_3v3_fighting)]]),
            NState = State;
        true ->
            NState = State
    end,
    {noreply, NState};

%% 刷出buff
do_handle_info({create_buff}, State) ->
    #center_pk_state{scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID} = State,
    create_buff([SceneID, ScenePoolId, RoomID]),
    {noreply, State};

do_handle_info(_Request, State) ->
    {noreply, State}.

%% 转换#team_score{}
to_team_score([#kf_3v3_team_data{team_id = TeamIDA, member_data = MemberDataA, map_power = MapPowerA},
    #kf_3v3_team_data{team_id = TeamIDB, member_data = MemberDataB, map_power = MapPowerB}]) ->
    if
        TeamIDA > TeamIDB ->
            GroupA = ?KF_3V3_GROUP_BLUE, GroupB = ?KF_3V3_GROUP_RED;
        true ->
            GroupA = ?KF_3V3_GROUP_RED, GroupB = ?KF_3V3_GROUP_BLUE
    end,
    RoleListA = to_role_score(MemberDataA, GroupA, []),
    RoleList = to_role_score(MemberDataB, GroupB, RoleListA),
    TeamScoreA = #team_score{team_id = TeamIDA, group = GroupA, map_power = MapPowerA},
    TeamScoreB = #team_score{team_id = TeamIDB, group = GroupB, map_power = MapPowerB},
    {[TeamScoreA, TeamScoreB], RoleList};
to_team_score(_) -> {[], []}.

%% 转换#role_score{}
to_role_score([], _, List) ->
    List;
to_role_score([Member | Rest], Group, List) ->
    #kf_3v3_role_data{
        server_name = ServerName, server_num = ServerNum, server_id = ServerId, role_id = RoleID,
        figure = Figure, power = Power, power_view = PowerView, season_pk = SeasonPk,
        % nickname = Nickname, sex = Sex, lv = RoleLv, vip = Vip, fashion_id = FashionID,
        % train_weapon = TWeapon, train_fly = TFly,
        sid = RoleSid, team_id = TeamID,
        tier = Tier, star = Star, continued_win = ContinuedWin, old_scene_info = OldScenInfo
    } = Member,
    RoleScore = #role_score{
        server_name = ServerName, server_num = ServerNum, server_id = ServerId, role_id = RoleID,
        figure = Figure, power = Power, power_view = PowerView, season_pk = SeasonPk,
        % nickname = Nickname, sex = Sex, lv = RoleLv, vip = Vip, fashion_id = FashionID,
        % train_weapon = TWeapon, train_fly = TFly,
        sid = RoleSid, team_id = TeamID, group = Group,
        tier = Tier, star = Star, continued_win = ContinuedWin, old_scene_info = OldScenInfo
    },
    to_role_score(Rest, Group, [RoleScore | List]).

%% 转换战力对比
to_power_contrast([], List) ->
    List;
to_power_contrast([#kf_3v3_team_data{
    team_id = TeamID, member_data = MemberData} | Rest], List) ->
    F = fun(
            #kf_3v3_role_data{
                server_name = ServerName, server_num = ServerNum, role_id = RoleID,
                figure = #figure{
                    name = Nickname, lv = Lv, vip = VipLv, career = Career, sex = Sex,
                    turn = Turn, picture = Picture, picture_ver = PictureVer},
                power_view = PowerView
                }
            , Data) ->
        [{TeamID, ServerName, ServerNum, RoleID, Nickname, PowerView, VipLv, Career, Sex, Lv, Turn, Picture, PictureVer} | Data]
    end,
    NList = lists:foldl(F, List, MemberData),
    to_power_contrast(Rest, NList).

%% 转换战场信息
to_battle_info(#center_pk_state{ed_time = EndTime, team_score = [TeamA, TeamB], role_score = RoleList}, TeamID) ->
    #team_score{team_id = TeamIDA, score = ScoreA} = TeamA,
    #team_score{team_id = TeamIDB, score = ScoreB} = TeamB,
    if
        TeamID == TeamIDA ->
            RoleBattle = to_role_battle(RoleList, TeamID, []),
            MyTeamID = TeamIDA, MyTeamScore = ScoreA,
            EnemyScore = ScoreB, EnemyTeamID = TeamIDB;
        TeamID == TeamIDB ->
            RoleBattle = to_role_battle(RoleList, TeamID, []),
            MyTeamID = TeamIDB, MyTeamScore = ScoreB,
            EnemyScore = ScoreA, EnemyTeamID = TeamIDA;
        true ->
            MyTeamID = 0, MyTeamScore = 0,
            RoleBattle = [], EnemyScore = 0, EnemyTeamID = 0
    end,
    LeftTime = erlang:max(EndTime - utime:unixtime(), 0),
    [?SUCCESS, LeftTime, MyTeamScore, MyTeamID, RoleBattle, EnemyScore, EnemyTeamID].

to_role_battle([], _, Data) ->
    Data;
to_role_battle([#role_score{team_id = TID} | Rest], TeamID, Data) when TID /= TeamID ->
    to_role_battle(Rest, TeamID, Data);
to_role_battle([#role_score{
        server_name = ServerName, server_num = ServerNum, role_id = RoleID,
        % nickname = Nickname, sex = Sex,
        figure = #figure{name = Nickname, career = Career, lv = Lv, sex = Sex, turn = Turn,
            picture = Picture, picture_ver = PictureVer},
        collect = Collect, kill = Kill, killed = Killed
    } | Rest], TeamID, Data) ->
    NData = [{ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Kill, Killed, Collect, Picture, PictureVer} | Data],
    to_role_battle(Rest, TeamID, NData).

%% 拉人进场景，分组，满血量
pull_into_room([], _) ->
    ok;
pull_into_room([#role_score{role_id = RoleID, server_id = ServerId, group = Group} | Rest], [SceneID, ScenePoolId, RoomID]) ->
    [{x, X}, {y, Y}] = lib_3v3_center:revive(Group),
    KeyValueList = [{group, Group}, {change_scene_hp_lim, 1}, {role_success_end_activity, {?MOD_KF_3V3, 1}} ],
    clusters_center:apply_cast(ServerId, lib_scene, change_player_scene,
        [RoleID, SceneID, ScenePoolId, RoomID, X, Y, KeyValueList]),
    pull_into_room(Rest, [SceneID, ScenePoolId, RoomID]).

%% 玩家重新PK战场
enter_pk_room(RoleList, [RoleID, SceneID, ScenePoolId, RoomID]) ->
   case lists:keyfind(RoleID, #role_score.role_id, RoleList) of
       #role_score{group = Group, server_id = ServerId} ->
           [{x, X}, {y, Y}] = lib_3v3_center:revive(Group),
           KeyValueList = [{group, Group}, {action_lock, ?ERRCODE(err650_in_kf_3v3_act)}],
           clusters_center:apply_cast(ServerId, lib_scene, change_player_scene,
               [RoleID, SceneID, ScenePoolId, RoomID, X, Y, KeyValueList]);
           % ?MODULE ! {get_battle_info, [ServerId, RoleSid, TeamID]};
       _ -> %% 检查第二组
           skip
   end.

%% 将房间内所有玩家踢出场景
%% @desc : 取消分组，回复血量 等状态更新在 lib_3v3_local 模块中
kick_out_room([ServerId, RoleID, OldScenInfo]) when is_integer(RoleID) ->
    clusters_center:apply_cast(ServerId, lib_3v3_local, kick_out_room, [RoleID, OldScenInfo]);
kick_out_room([UserList, RoleList]) ->
    F = fun(#ets_scene_user{id = RoleID, server_id = ServerId}) ->
        case lists:keyfind(RoleID, #role_score.role_id, RoleList) of
            #role_score{old_scene_info = OldScenInfo} -> ok;
            _ -> OldScenInfo = undefined
        end,
        clusters_center:apply_cast(ServerId, lib_3v3_local, kick_out_room, [RoleID, OldScenInfo])
    end,
    lists:foreach(F, UserList);
kick_out_room(_) -> ok.

%% 发送双方的战力对比
send_power_contrast(TeamA, TeamB) ->
    Data = to_power_contrast([TeamA, TeamB], []),
    #kf_3v3_team_data{member_data = MemberDataA} = TeamA,
    #kf_3v3_team_data{member_data = MemberDataB} = TeamB,
    F = fun(#kf_3v3_role_data{server_id = ServerId, role_id = RoleID}) ->
        clusters_center:apply_cast(ServerId, lib_3v3_local, send_power_contrast, [[RoleID, Data]])
    end,
    lists:foreach(F, MemberDataA ++ MemberDataB).

%% 发送神塔采集广播
send_occupy_tower(RoleList) ->
    F = fun(#role_score{server_id = ServerId, sid = RoleSid}) ->
        clusters_center:apply_cast(ServerId, mod_3v3_local, send_occupy_tower, [[RoleSid]])
    end,
    lists:foreach(F, RoleList).

%% 发送积分变更广播
send_score_notice([#team_score{group = GroupA, score = ScoreA},
    #team_score{group = GroupB, score = ScoreB}], RoleList) ->
    if
        GroupA > GroupB ->
            Data = [ScoreB, ScoreA];
        true ->
            Data = [ScoreA, ScoreB]
    end,
    F = fun(#role_score{server_id = ServerId, sid = RoleSid}) ->
        clusters_center:apply_cast(ServerId, mod_3v3_local, send_score_notice, [[RoleSid, Data]])
    end,
    lists:foreach(F, RoleList).

%% 发送玩家战场数据变更广播
send_role_score(RoleList, Group, Data) ->
    F = fun(#role_score{server_id = ServerId, sid = RoleSid, group = TGroup}) ->
        if
            TGroup == Group ->
                clusters_center:apply_cast(ServerId, mod_3v3_local, send_role_score, [[RoleSid, Data]]);
            true -> skip
        end
    end,
    lists:foreach(F, RoleList).

%% 推送战斗结算
send_pk_result(RoleList, Data) ->
    F = fun(#role_score{
            server_id = ServerId, role_id = RoleID, honor = Honor,
            tier = Tier, star = Star, continued_win = ContinuedWin
        }) ->
        clusters_center:apply_cast(ServerId, lib_3v3_local, send_pk_result, [[RoleID, Tier, Star, Honor, ContinuedWin, Data]])
    end,
    lists:foreach(F, RoleList).

reset_online_all(RoleList, UserList) when is_list(UserList) ->
    F = fun(#role_score{role_id = RoleID} = R, List) ->
        case lists:keyfind(RoleID, #ets_scene_user.id, UserList) of
            #ets_scene_user{} ->
                [R#role_score{online = ?PK_3V3_ONLINE} | List];
            _ ->
                [R#role_score{online = ?PK_3V3_OFFLINE} | List]
        end
    end,
    lists:foldl(F, [], RoleList);
reset_online_all(RoleList, _) -> RoleList.

%% 队伍增加积分
%% @desc : 率先超过300积分的队伍获胜
add_score_team([#team_score{group = GroupA, score = OldScoreA} = TeamA,
    #team_score{group = GroupB, score = OldScoreB} = TeamB], [Group, Score]) ->
    if
        Group == GroupA ->
            if
                OldScoreA + Score >= ?PK_3V3_MAX_SCORE ->
                    catch self() ! {stop_fight};
                true -> skip
            end,
            [TeamA#team_score{score = OldScoreA + Score}, TeamB];
        Group == GroupB ->
            if
                OldScoreB + Score >= ?PK_3V3_MAX_SCORE ->
                    catch self() ! {stop_fight};
                true -> skip
            end,
            [TeamA, TeamB#team_score{score = OldScoreB + Score}];
        true ->
            [TeamA, TeamB]
    end.

%% 玩家增加积分
%% 击杀1人 + 2积分
add_score_role(State, RoleList, RoleID, KeyValueList) ->
    #center_pk_state{scene_id = SceneID, scene_pool_id = ScenePoolId, room_id = RoomID} = State,
    case lists:keyfind(RoleID, #role_score.role_id, RoleList) of
        #role_score{group = Group} = RoleScore ->
            F =  fun({Key, Val}, R) ->
                case Key of
                    collect ->
                        R#role_score{collect = R#role_score.collect + Val};
                    kill ->
                        R#role_score{kill = R#role_score.kill + Val};
                    killed ->
                        R#role_score{killed = R#role_score.killed + Val};
                    continued_kill when Val>0 ->
                        R#role_score{continued_kill = R#role_score.continued_kill + Val};
                    continued_kill ->
                        R#role_score{continued_kill = Val};
                    assist ->
                        R#role_score{assist = R#role_score.assist + Val};
                    _ ->
                        R
                end
            end,
            NRoleScore = lists:foldl(F, RoleScore, KeyValueList),
            NRoleList = lists:keyreplace(RoleID, #role_score.role_id, RoleList, NRoleScore),
            #role_score{
                server_name = ServerName, server_num = ServerNum, role_id = RoleID, kill = Kill,
                killed = Killed, collect = Collect, figure = Figure, continued_kill = ContinuedKill
            } = NRoleScore,
            #figure{
                name = Nickname, career = Career, turn = Turn, picture = Picture,
                picture_ver = PictureVer} = Figure,
            Data = [ServerName, ServerNum, RoleID, Kill, Killed, Collect],
            %% 推送玩家积分变更广播
            send_role_score(NRoleList, Group, Data),
            IsFromKill = lists:keyfind(continued_kill, 1, KeyValueList),
            %% 连杀传闻
            if
                IsFromKill=/=false andalso ContinuedKill>0 ->
                    {ok, BinData} = pt_650:write(65044, [RoleID, Nickname, Career, Turn, Picture, PictureVer, ContinuedKill]),
                    % 编码可能有问题,用进程发送
                    spawn(fun() ->
                        lib_server_send:send_to_scene(SceneID, ScenePoolId, RoomID, BinData),
                        lib_chat:send_TV({scene, SceneID, ScenePoolId, RoomID}, ?MOD_KF_3V3, 7, [Nickname, ContinuedKill])
                    end);
                true -> skip
            end,
            NRoleList;
        _ ->
            RoleList
    end.

%% 神塔每5s + 2积分，超过一分钟，每5s + 5积分
occupy_tower(TowerData, MonID, Group) ->
    NMonID = lib_3v3_center:get_tower_id(Group, MonID),
    %% 删除MonID
    case lists:keyfind(MonID, #tower_data.mon_id, TowerData) of
        #tower_data{group = G1} when G1 /= Group ->
            TowerData1 = lists:keydelete(MonID, #tower_data.mon_id, TowerData);
        _ ->
            TowerData1 = TowerData
    end,
    %% 新增NMonID
    case lists:keyfind(NMonID, #tower_data.mon_id, TowerData1) of
        #tower_data{group = G2} when G2 == Group ->
            TowerData1;
        _ ->
            TowerInfo = #tower_data{mon_id = NMonID, time = utime:unixtime(), group = Group},
            [TowerInfo | TowerData1]
    end.

%% 战斗结束
leave_team(RoleList) ->
    {AList, BList, LeaveList} = leave_team_handler(RoleList, [], [], [], {0, 0}),
    mod_3v3_center:update_unite_data([AList, BList, LeaveList]).

leave_team_handler([], AList, BList, LeaveList, {TeamIDA, TeamIDB}) ->
    {{TeamIDA, AList}, {TeamIDB, BList}, LeaveList};
leave_team_handler([#role_score{
        server_name = ServerName, server_num = ServerNum, server_id = ServerId, role_id = RoleID,
        sid = RoleSid, tier = Tier, star = Star, season_pk = SeasonPk,
        continued_win = ContinuedWin, group = Group, team_id = TeamID,
        online = IsOnline} | Rest], AList, BList, LeaveList, {TeamIDA, TeamIDB}) ->
    if
        %% 将不在线的玩家数据清除
        IsOnline == ?PK_3V3_OFFLINE ->
            NLeaveList = [[ServerName, ServerNum, ServerId, RoleID, RoleSid] | LeaveList];
        true ->
            NLeaveList = LeaveList
    end,
    if
        Group == ?KF_3V3_GROUP_BLUE ->
            NAList = [{RoleID, [{pk_pid, 0}, {group, 0}, {tier, Tier}, {star, Star},
                {continued_win, ContinuedWin}, {season_pk, SeasonPk}]} | AList],
            leave_team_handler(Rest, NAList, BList, NLeaveList, {TeamID, TeamIDB});
        true ->
            NBList = [{RoleID, [{pk_pid, 0}, {group, 0}, {tier, Tier}, {star, Star},
                {continued_win, ContinuedWin}, {season_pk, SeasonPk}]} | BList],
            leave_team_handler(Rest, AList, NBList, NLeaveList, {TeamIDA, TeamID})
    end.

%% ========================= 结算战斗积分 ==========================
%% 1.正常结束
%%  活动持续3分钟，结束时，哪方占领的塔数多，哪方获胜，如果塔数一样，总积分多的一方获胜
%%      增加积分的时候，塔顶需要飘字：xxx队+yyy分
%%  占领塔的数量 > 战斗积分 > 队伍匹配战力
%%      增加积分的时候，人物头顶需要飘字：xxx队+yyy分
%%  如果都一样，则为平局，所有玩家的竞技积分和荣耀积分不变

%% 2.提前结束
%%  如果某方提前达到300分则提前结束游戏
%% =================================================================
calc_result_room([#team_score{score = ScoreA, group = GroupA, map_power = _MapPowerA},
    #team_score{score = ScoreB, group = GroupB, map_power = _MapPowerB}], TowerData, RoleList) ->
    F = fun(#tower_data{group = OccupyID}, {TA, TB}) ->
        if
            OccupyID == GroupA -> {TA + 1, TB};
            OccupyID == GroupB -> {TA, TB + 1};
            true ->               {TA, TB}
        end
    end,
    {TowerA, TowerB} = lists:foldl(F, {0, 0}, TowerData),
    if
        TowerA > TowerB orelse
        (ScoreA >= ?PK_3V3_MAX_SCORE andalso ScoreA > ScoreB) ->
            Result = GroupA, WinTower = TowerA, LoseTower = TowerB, WinGroup = GroupA; %% A队胜利
        TowerA < TowerB orelse
        (ScoreB >= ?PK_3V3_MAX_SCORE andalso ScoreA < ScoreB) ->
            Result = GroupB, WinTower = TowerB, LoseTower = TowerA, WinGroup = GroupB; %% B队胜利
        ScoreA > ScoreB ->
            Result = GroupA, WinTower = TowerA, LoseTower = TowerB, WinGroup = GroupA; %% A队胜利
        ScoreB > ScoreA ->
            Result = GroupB, WinTower = TowerB, LoseTower = TowerA, WinGroup = GroupB; %% B队胜利
        true ->
            Result = ?KF_3V3_RESULT_DRAW, WinTower = TowerA, LoseTower = TowerB, WinGroup = GroupA %% 打平
    end,
    %% PS : Data发生变化需要修改一下所有函数
    case Result == ?KF_3V3_RESULT_DRAW of
        true -> WinType = draw, LoseType = draw;
        false -> WinType = win, LoseType = lose
    end,
    % 依然需要WinGroup 抽取数据
    {WinnerList, LoserList} = calc_result_role(RoleList, WinGroup, {[], []}),
    NWinnerList = calc_mvp(sort_score(WinnerList), 0, WinType, []),
    NLoserList = calc_mvp(sort_score(LoserList), 0, LoseType, []),
    RoleList1 = get_tier_star(NWinnerList, WinType, RoleList),
    NRoleList = get_tier_star(NLoserList, LoseType, RoleList1),
    {[Result, WinTower, NWinnerList, LoseTower, NLoserList], NRoleList}.

%% 计算各玩家积分
calc_result_role([], _, Result) ->
    Result;
calc_result_role([#role_score{group = Group, server_name = ServerName, server_num = ServerNum,
    role_id = RoleID, kill = Kill, killed = Killed, collect = Collect, assist = Assist,
    power_view = PowerView, figure = #figure{name = Nickname, career = Career, sex = Sex, lv = Lv, turn = Turn,
    picture = Picture, picture_ver = PictureVer} } | Rest], WinGroup, {WinnerList, LoserList}) ->
    if
        Killed == 0 ->
            Score = (1.5 * Kill + Assist + 0.5 * Collect); %% 玩家积分值
        true ->
            Score = (1.5 * Kill + Assist + 0.5 * Collect) / Killed %% 玩家积分值
    end,
    Data = {ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, PowerView, Kill, Killed, Collect, Score, Picture, PictureVer},
    if
        Group == WinGroup ->
            calc_result_role(Rest, WinGroup, {[Data | WinnerList], LoserList});
        true ->
            calc_result_role(Rest, WinGroup, {WinnerList, [Data | LoserList]})
    end.

%% ========================= MVP 计算公式 ==============================
%% K：K头数
%% A：助攻数
%% D：死亡数
%% T：占塔数
%%
%% 胜方MVP：   获胜一方的人当中
%%  评分=(1.5*K+A+0.5*T)/D            最高者得MVP
%%
%% 败方MVP：   失败一方的人当中
%%  满足两个条件才出现：
%%  K>5 &   (1.5*K+A+0.5*T)/D > 2.5
%%
%% 暂时没有助攻，则A=0
%% ======================================================================
calc_mvp([], _, _, List) ->
    List;
calc_mvp([{ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Power, Kill, Killed, Collect, Score, Picture, PictureVer} | Rest],
    I, Type, List) ->
    if
        Type == win andalso I == 0 ->
            Data = {ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Power, Kill, Killed, Collect, 1, Picture, PictureVer},
            calc_mvp(Rest, I + 1, Type, [Data | List]);
        Type == lose andalso I == 0 andalso Score > 2.5 andalso Kill > 5 ->
            Data = {ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Power, Kill, Killed, Collect, 1, Picture, PictureVer},
            calc_mvp(Rest, I + 1, Type, [Data | List]);
        Type == draw andalso I == 0 andalso Score > 2.5 andalso Kill > 5 ->
            Data = {ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Power, Kill, Killed, Collect, 1, Picture, PictureVer},
            calc_mvp(Rest, I + 1, Type, [Data | List]);
        true ->
            Data = {ServerName, ServerNum, RoleID, Nickname, Career, Sex, Lv, Turn, Power, Kill, Killed, Collect, 0, Picture, PictureVer},
            calc_mvp(Rest, I + 1, Type, [Data | List])
    end.

%% 积分排序 - 降序
sort_score(List) ->
    F = fun({_, _, _, _, _, _, _, _, PowerA, _, _, _, ScoreA, _, _}, {_, _, _, _, _, _, _, _, PowerB, _, _, _, ScoreB, _, _}) ->
        if
            ScoreA > ScoreB -> true;
            ScoreA < ScoreB -> false;
            true -> PowerA >= PowerB
        end
    end,
    lists:sort(F, List).

%% ======================== 计算段位星数 ================================
%% 1，玩家初始状态1星，可以通过3V3战斗，获得星数加减
%%  途径有：
%%      加：战斗胜利，MVP，连胜奖励
%%      减：战斗失败
%% 2，玩家参与3V3玩法，战斗获胜，星数+2，战斗失败，星数-1
%% 3，段位与星数的关系
%%  满足条件的星数，即进入下一段，段位头衔改变。
%% 4，保护措施：最低段位（青铜段位）的玩家，失败不掉星
%% 5，连胜奖励：从第3场连胜开始，玩家每连胜一次，可额外获得+1星奖励
%% 6，MVP：每局战斗结算，根据玩家战场表现，评选MVP，MVP获得星数+1
%% =====================================================================
get_tier_star([], _, RoleList) ->
    RoleList;
get_tier_star([{ServerName, ServerNum, RoleID, _, _, _, _, _, _, _, _, _, IsMVP, _, _} | Rest],
    Type, RoleList) ->
    case get_role_score(RoleList, [ServerName, ServerNum, RoleID]) of
        {ok, #role_score{continued_win = ContinuedWin,
            tier = Tier, star = Star, season_pk = SeasonPk} = RoleScore} ->
            {NTier, NStar, Honor, NContinuedWin} =
                calc_tier_star(Type, Tier, Star, IsMVP, ContinuedWin),
            NRoleScore = RoleScore#role_score{tier = NTier, star = NStar,
                continued_win = NContinuedWin, honor = Honor, season_pk = SeasonPk + 1},
            NRoleList = lists:keyreplace(RoleID, #role_score.role_id, RoleList, NRoleScore),
            get_tier_star(Rest, Type, NRoleList);
        _ ->
            get_tier_star(Rest, Type, RoleList)
    end.

-define(MVP_START, 3).
%% 计算段位星数 & 荣誉奖励
%% @return : {Tier, Star, Honor}
calc_tier_star(Type, Tier, Star, IsMVP, ContinuedWin) ->
    case data_3v3:get_tier_info(Tier) of
        #tier_info{star = NeedStar, win_star = WinStar, lose_star = LoseStar,
            win_reward = WinReward, lose_reward = LoseReward} ->
            ContinuedWinStar = data_3v3:get_win_row(ContinuedWin + 1),
            if
                Type == win andalso IsMVP == 1 ->
                    {NTier, NStar} = calc_tier_star_handler(
                        Tier, Star, WinStar + ContinuedWinStar + ?MVP_START, NeedStar),
                    {NTier, NStar, WinReward, ContinuedWin + 1};
                Type == win ->
                    {NTier, NStar} = calc_tier_star_handler(
                        Tier, Star, WinStar + ContinuedWinStar, NeedStar),
                    {NTier, NStar, WinReward, ContinuedWin + 1};
                Type == lose andalso IsMVP == 1 ->
                    {NTier, NStar} = calc_tier_star_handler(
                        Tier, Star, LoseStar + ?MVP_START, NeedStar),
                    {NTier, NStar, LoseReward, 0};
                Type == draw andalso IsMVP == 1 ->
                    {NTier, NStar} = calc_tier_star_handler(
                        Tier, Star, LoseStar + ?MVP_START, NeedStar),
                    {NTier, NStar, LoseReward, 0};
                true ->
                    {NTier, NStar} = calc_tier_star_handler(
                        Tier, Star, LoseStar, NeedStar),
                    {NTier, NStar, LoseReward, 0}
            end;
        _ ->
            {Tier, Star, 0, 0}
    end.

%% 新的段位星数
calc_tier_star_handler(Tier, Star, AddStar, _NeedStar) ->
    NStar = Star + AddStar,
    lib_3v3_local:calc_tier_by_star(Tier, NStar).
    % if
    %     NStar > Star ->
    %         case data_3v3:get_tier_info(Tier + 1) of
    %             #tier_info{star = NextStar} when NStar < NextStar ->
    %                 {Tier, NStar};
    %             #tier_info{star = NextStar} when NStar >= NextStar ->
    %                 {Tier + 1, NStar};
    %             _ ->
    %                 {Tier, NeedStar}
    %         end;
    %     NStar < Star andalso NStar < NeedStar ->
    %         case data_3v3:get_tier_info(Tier - 1) of
    %             #tier_info{} ->
    %                 {Tier - 1, erlang:max(NStar, 0)};
    %             _ ->
    %                 {Tier, erlang:max(NStar, 0)}
    %         end;
    %     true ->
    %         {Tier, NStar}
    % end.

get_role_score(RoleList, [ServerName, ServerNum, RoleID]) ->
    get_role_score_handler(RoleList, [ServerName, ServerNum, RoleID]).

get_role_score_handler([], _) ->
    false;
get_role_score_handler([#role_score{server_name = SN, server_num = S, role_id = ID
    } = RoleScore | Rest], [ServerName, ServerNum, RoleID]) ->
    case {ServerName, ServerNum, RoleID} of
        {SN, S, ID} ->
            {ok, RoleScore};
        _ ->
            get_role_score_handler(Rest, [ServerName, ServerNum, RoleID])
    end.

%% 刷新3v3排行榜
refresh_3v3_rank(RoleList) ->
    NowTime = utime:unixtime(),
    F = fun(
            #role_score{
                server_name = ServerName, server_num = ServerNum, server_id = ServerId, role_id = RoleID,
                figure = #figure{name = Nickname, lv = Lv, career = Career, sex = Sex, vip = VipLv},
                power_view = PowerView, tier = Tier, star = Star, season_pk = SeasonPk}
            , List
            ) ->
        RoleRank = #kf_3v3_rank_data{
            server_name = ServerName, server_num = ServerNum, server_id = ServerId, role_id = RoleID,
            nickname = Nickname, career = Career, sex = Sex, lv = Lv, vip_lv = VipLv,
            power = PowerView, tier = Tier, star = Star, time = NowTime, season_pk = SeasonPk
            },
        [RoleRank | List]
    end,
    RankList = lists:foldl(F, [], RoleList),
    mod_3v3_rank:refresh_3v3_rank(RankList).

%% 生成怪物
create_mons([SceneID, ScenePoolId, RoomID]) ->
    TowerInfo = lib_3v3_center:get_tower_info(),
    TowerData = create_towers(TowerInfo, [SceneID, ScenePoolId, RoomID], []),
    GuardianInfoL = lib_3v3_center:get_guardian_info(),
    create_guardians(GuardianInfoL, [SceneID, ScenePoolId, RoomID]),
    TowerData.

%% 生成神塔
create_towers([], _, TowerData) ->
    TowerData;
create_towers([{MonID, {X, Y}} | Rest], [SceneID, ScenePoolId, RoomID], TowerData) ->
    case data_mon:get(MonID) of
        #mon{type = Type} ->
            CollectHandler = {?MODULE, tower_be_collected, self()},
            lib_mon:async_create_mon(MonID, SceneID, ScenePoolId, X, Y, Type, RoomID, 1, [{collected_handler, CollectHandler}]),
            NTowerData = [#tower_data{mon_id = MonID} | TowerData];
        _ ->
            NTowerData = TowerData
    end,
    create_towers(Rest, [SceneID, ScenePoolId, RoomID], NTowerData).

%% 生成守护神
create_guardians([], _) ->
    ok;
create_guardians([{MonID, X, Y, Args} | Rest], [SceneID, ScenePoolId, RoomID]) ->
    case data_mon:get(MonID) of
        #mon{type = Type} ->
            lib_mon:async_create_mon(MonID, SceneID, ScenePoolId, X, Y, Type, RoomID, 1, Args);
        _ -> skip
    end,
    create_guardians(Rest, [SceneID, ScenePoolId, RoomID]).

%% 生成buff怪
create_buff([SceneID, ScenePoolId, RoomID]) ->
    BuffList = lib_3v3_center:get_buff_info(),
    CollectHandler = {?MODULE, buff_be_collected, self()},
    case urand:list_rand_by_weight(BuffList, 2) of
        [BuffMonId1, BuffMonId2|_] ->
            {X1, Y1} = lib_3v3_center:get_buff_xy(?KF_3V3_GROUP_BLUE),
            {X2, Y2} = lib_3v3_center:get_buff_xy(?KF_3V3_GROUP_RED),
            lib_mon:async_create_mon(BuffMonId1, SceneID, ScenePoolId, X1, Y1, 0, RoomID, 1, [{collected_handler, CollectHandler}]),
            lib_mon:async_create_mon(BuffMonId2, SceneID, ScenePoolId, X2, Y2, 0, RoomID, 1, [{collected_handler, CollectHandler}]),
            BuffMonName1 = get_mon_name(BuffMonId1),
            BuffMonName2 = get_mon_name(BuffMonId2),
            spawn(fun() -> lib_chat:send_TV({scene, SceneID, ScenePoolId, RoomID}, ?MOD_KF_3V3, 6, [BuffMonName1, BuffMonName2]) end);
        _ -> skip
    end.

get_mon_name(MonId) ->
    case data_mon:get(MonId) of
        #mon{name = MonName} -> MonName;
        _ -> ""
    end.

%% 日志
log(State, Data, NRoleList) ->
    #center_pk_state{room_id = RoomID} = State,
    NowTime = utime:unixtime(),
    <<PkId:48>> = <<NowTime:32, RoomID:16>>,
    [Result, _WinTower, NWinnerList, _LoseTower, NLoserList] = Data,
    log_3v3_pk_room(State, PkId, Result),
    log_3v3_pk_team(State#center_pk_state.team_score, PkId, Result),
    log_3v3_pk_role(NWinnerList++NLoserList, PkId, Result, NRoleList, State#center_pk_state.role_score),
    ok.

log_3v3_pk_room(
        #center_pk_state{
            scene_id = SceneId, scene_pool_id = ScenePoolId, room_id = RoomId, tower_data = TowerData,
            role_score = RoleList, team_score = TeamScoreL
            }
        , PkId, Result) ->
    F = fun(#tower_data{mon_id = MonId, time = Time, group = Group}) -> {MonId, Time, Group} end,
    TowerDataF = [F(T)||T<-TowerData],
    BRoleList = [Name||#role_score{figure = #figure{name = Name}, group = Group}<-RoleList, Group == ?KF_3V3_GROUP_BLUE],
    RRoleList = [Name||#role_score{figure = #figure{name = Name}, group = Group}<-RoleList, Group == ?KF_3V3_GROUP_RED],
    case BRoleList of
        [BName1, BName2, BName3|_] -> ok;
        [BName1, BName2] -> BName3 = "";
        [BName1] -> BName2 = "", BName3 = "";
        _ -> BName1 = "", BName2 = "", BName3 = ""
    end,
    case RRoleList of
        [RName1, RName2, RName3|_] -> ok;
        [RName1, RName2] -> RName3 = "";
        [RName1] -> RName2 = "", RName3 = "";
        _ -> RName1 = "", RName2 = "", RName3 = ""
    end,
    case lists:keyfind(?KF_3V3_GROUP_BLUE, #team_score.group, TeamScoreL) of
        false -> BScore = 0;
        #team_score{score = BScore} -> ok
    end,
    case lists:keyfind(?KF_3V3_GROUP_RED, #team_score.group, TeamScoreL) of
        false -> RScore = 0;
        #team_score{score = RScore} -> ok
    end,
    BTowerNum = length([Group||#tower_data{group = Group}<-TowerData, Group == ?KF_3V3_GROUP_BLUE]),
    RTowerNum = length([Group||#tower_data{group = Group}<-TowerData, Group == ?KF_3V3_GROUP_RED]),
    lib_log_api:log_3v3_pk_room(SceneId, ScenePoolId, RoomId, TowerDataF, PkId, Result, BName1, BName2, BName3, BScore,
        BTowerNum, RName1, RName2, RName3, RScore, RTowerNum),
    ok.

log_3v3_pk_team([], _PkId, _Result) -> skip;
log_3v3_pk_team([#team_score{
        team_id = TeamId, group = Group, score = Score, kill = Kill,
        killed = Killed, assist = Assist}|T]
        , PkId, Result) ->
    lib_log_api:log_3v3_pk_team(PkId, TeamId, Group, Score, Kill, Killed, Assist, Result),
    log_3v3_pk_team(T, PkId, Result).

log_3v3_pk_role([], _PkId, _Result, _NRoleList, _ORoleList) -> skip;
log_3v3_pk_role([{_Platform, _ServerNum, RoleId, Name, _Career, _Sex, _Lv, _Turn, _Power, Kill, Killed, Collect, IsMvp, _Picture, _PictureVer}|T], PkId, Result, NRoleList, ORoleList) ->
    case lists:keyfind(RoleId, #role_score.role_id, NRoleList) of
        false -> NewTier = 0, NewStar = 0, NewContinuedWin = 0, Honor = 0, Assist = 0, Group = 0;
        #role_score{tier = NewTier, star = NewStar, continued_win = NewContinuedWin, honor = Honor, assist = Assist, group = Group} -> ok
    end,
    case lists:keyfind(RoleId, #role_score.role_id, ORoleList) of
        false -> OldTier = 0, OldStar = 0, OldContinuedWin = 0;
        #role_score{tier = OldTier, star = OldStar, continued_win = OldContinuedWin} -> ok
    end,
    lib_log_api:log_3v3_pk_role(PkId, RoleId, Name, Group, OldTier, OldStar, OldContinuedWin, NewTier, NewStar, NewContinuedWin,
        Kill, Killed, Collect, Assist, Honor, IsMvp, Result),
    log_3v3_pk_role(T, PkId, Result, NRoleList, ORoleList).

tower_be_collected(Minfo, _CollectorServerId, _CollectorNode, CollectorId, BattlePid) ->
    #scene_object{scene = SceneID, scene_pool_id = ScenePoolId, copy_id = RoomID, config_id = MonID} = Minfo,
    spawn(fun() ->
        timer:sleep(1200),
        BattlePid ! {tower_collect_complete, [SceneID, ScenePoolId, RoomID, CollectorId, MonID]}
    end).

buff_be_collected(Minfo, _CollectorServerId, CollectorNode, CollectorId, BattlePid) ->
    #scene_object{scene = SceneID, scene_pool_id = ScenePoolId, copy_id = RoomID, config_id = MonID, skill = Skill} = Minfo,
    case Skill of
        [{SkillId, SkillLv}|_] -> BattlePid ! {buff_collect_complete, [SceneID, ScenePoolId, RoomID, CollectorNode, CollectorId, MonID, SkillId, SkillLv]};
        _ -> skip
    end.
