%% ---------------------------------------------------------------------------
%% @doc 跨服帮战
%% @author zhaoyu
%% @since  2018-08-30
%% ---------------------------------------------------------------------------
-module(cross_guild_war_api).

-include("cross_guild_war.hrl").
-include("guild_war.hrl").
-include("errcode.hrl").
-include("battle.hrl").
-include("scene.hrl").
-include("attr.hrl").
-include("guild.hrl").
-include("figure.hrl").
-include("server.hrl").
-include("goods.hrl").
-include("predefine.hrl").
-include("vip.hrl").
-include("def_module.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("dungeon.hrl").
-include("czone.hrl").
-include("def_fun.hrl").
-include("common.hrl").
-include("chat.hrl").

-export([
        sign_up/2                               %% 报名
        ,enter_scene/1                          %% 进入场景
        ,hosting_enter_scene/1                  %% 托管无判断
        ,enter_scene_function/7                 %% 进入跨服帮战场景
        ,add_log/5                              %% 参与日志
        ,log_cross_guild_war_conquer/4          %% 占领日志
        ,log_cross_guild_war_support/7          %% 应援日志
        ,leave_scene/1                          %% 离开跨服帮战场景
        ,leave_scene_function/1                 %% 离开跨服帮战场景
        ,send_battlefield_info/1                %% 战场信息
        ,send_guild_direction/2                 %% 发出号令
        ,support_guild/3                        %% 应援帮派
        ,support_guild_callback/1               %% 应援帮派callback
        ,send_support_list/1                    %% 应援列表
        ,get_city_award/2                       %% 领取占领城池奖励
        ,get_city_award_callback/2              %% 领取占领城池奖励
        ,send_city_info/1                       %% 上次活动中城池占领信息
        ,del_role_cgw/0                         %% 活动结束清除玩家应援和领取奖励记录
        ,reset_role_cgw/1                       %% 重置玩家应援和领取奖励记录
        ,mark_sign_cancle/1                     %% 记录取消时间
        ,handle_event/2                         %% 客户端断开连接或者角色进程退出
        ,prohibit_talk/2                        %% 霸主特权-禁言
        ,faction_rename/3                       %% 霸主特权-国家改名
        ,rename_callback/4
        ,overlord_buy/1                         %% 霸主限购-购买
        ,get_goods_info/1
        ,load_overlord_info/1
        ,cancel_overlord/0                      %% 取消霸主身份
        ,do_cancel_overlord/1
        ,sync_guild_chief/3
    ]).

-export([
        is_in_cross_guild_war/1                 %% 是否处于跨服帮战场景中
        ,get_born_xy/3                          %% 获取复活坐标
        ,get_revive_xy/3
        ,get_battle_xy/3
        ,appoint_king/1
        ,quasi_appoint_king/1
        ,do_appoint_king/2
        ,king_idn/1
        ,get_mon_name/2
    ]).

-export([
        attack_mon/4                            %% 玩家攻击怪
        ,kill_mon/2                             %% 玩家击杀怪
    ]).

-export([
        merge_server/2,                        %% 合服处理
        gm/1,
        gm_guild/1,
        gm_reset_data/1
    ]).


%%跨服中心过来拿团长头像数据
sync_guild_chief(ChiefId,Group,Pid)->
    Figure = lib_role:get_role_figure(ChiefId),
    RecFigure = lib_role:figure_to_rec_picture(Figure),
    Msg = {update_chief_info, Group, RecFigure},
    clusters_node:apply_cast(cross_guild_war_battle,cast,[Pid, Msg]).


%% ---------------------------------------------------------------------------
%% @doc 是否处于跨服帮战场景中
-spec is_in_cross_guild_war(SceneId) -> Return when
    SceneId     :: integer(),
    Return      :: true | false.
%% ---------------------------------------------------------------------------
is_in_cross_guild_war(SceneId) ->
    case data_cross_guild_war:get_config(scene_id) of
        SceneId -> true;
        _ -> false
    end.

%%霸主身份
king_idn(Status)->
    #player_status{id=RoleID,figure=Figure}=Status,
    case RoleID == game_env:get(cgw_king) of
        true->
            OverlordInfo = load_overlord_info(RoleID),
            Status#player_status{figure=Figure#figure{king=1}, overlord_privilege = OverlordInfo};
        _->
            QuasiList = game_env:get(quasi_cgw_king),
            QuasiList2 = ?IF(is_list(QuasiList), QuasiList, []),
            case lists:member(RoleID, QuasiList2) of
                true->
                    Status#player_status{figure=Figure#figure{king=2}};
                _->
                    Status
            end
    end.

%%霸主任命
appoint_king(ChiefId)->
    game_env:save(cgw_king,ChiefId),
    lib_player:apply_cast(ChiefId,?APPLY_CAST_SAVE, ?MODULE, do_appoint_king,[1]),
    ok.

%%准霸主任命
quasi_appoint_king(ChiefId)->
    case game_env:get(quasi_cgw_king) of
        ChiefIds when is_list(ChiefIds) ->
            game_env:save(quasi_cgw_king, [ChiefId|ChiefIds]);
        _ ->
            game_env:save(quasi_cgw_king, [ChiefId])
    end,
    lib_player:apply_cast(ChiefId,?APPLY_CAST_SAVE, ?MODULE, do_appoint_king,[2]),
    ok.

do_appoint_king(Status, King) ->
    #player_status{id = RoleId, sid = Sid, figure=Figure}=Status,
    NFigure = Figure#figure{king=King},
    NStatus = Status#player_status{figure=NFigure},
    mod_scene_agent:update(NStatus,[{cgw_king,King}]),
    {ok, BinData} = pt_601:write(60124, [King]),
    lib_server_send:send_to_sid(Sid, BinData),
    lib_role:update_role_show(RoleId, [{figure, NFigure}]),
    {ok, NStatus}.


%% ---------------------------------------------------------------------------
%% @doc 玩家攻击怪
-spec attack_mon(Attacker, MonInfo, Hurt, IsFirstAttack) -> ok when
    Attacker        :: #battle_return_atter{},
    MonInfo         :: #scene_object{},
    Hurt            :: integer(),
    IsFirstAttack   :: true | false.
%% ---------------------------------------------------------------------------
attack_mon(Attacker, MonInfo, _Hurt, IsFirstAttack) ->
    #battle_return_atter{id = RoleId, guild_id = GuildId,group=AttGroup} = Attacker,
    #scene_object{
        mon = #scene_mon{mid = MonId}, scene = SceneId, id = _MonUid
        ,battle_attr = #battle_attr{hp = Hp, group = Group}, copy_id = CopyId
    } = MonInfo,
    Alive = misc:is_process_alive(CopyId),
    case is_in_cross_guild_war(SceneId) andalso Alive of
        true  ->
            Msg = {attack_mon, RoleId, GuildId,AttGroup,MonId, Hp, Group, IsFirstAttack},
            cross_guild_war_battle:cast(CopyId, Msg);
        _ ->
            ignore
    end.


%% ---------------------------------------------------------------------------
%% @doc 玩家击杀怪
-spec kill_mon(Attacker, MonInfo) -> ok when
    Attacker        :: #battle_return_atter{},
    MonInfo         :: #scene_object{}.
%% ---------------------------------------------------------------------------
kill_mon(Attacker, MonInfo) ->
    #scene_object{scene = SceneId, copy_id = CopyId} = MonInfo,
    Alive = misc:is_process_alive(CopyId),
    case is_in_cross_guild_war(SceneId) andalso Alive of
        true  ->
            Msg = {kill_mon, Attacker, MonInfo},
            cross_guild_war_battle:cast(CopyId, Msg);
        _ ->
            ignore
    end.


%% ---------------------------------------------------------------------------
%% @doc 报名
sign_up(OpTy,Role) ->
    #player_status{
        id = RoleId, guild = GuildStatus, combat_power = Power
        ,figure = Figure, sid = Sid,cross_guild_war = RoleCgw
    } = Role,
    #figure{
        name = RoleName, position = Position, lv= Lev, vip = Vip,sup_vip=SVip,sex=Sex
    } = Figure,
    #status_guild{id = GuildId} = GuildStatus,
    CurS = cross_guild_war_local:get_local_state(),
    IsCd = RoleCgw#role_cgw.last_sign+data_cross_guild_war:get_config(resign_time)>utime:unixtime(),
    if
        CurS /= ?CGW_ST_SIGN ->
            {false, ?ERRCODE(err601_cant_sign_now)};
        GuildId =< 0 ->
            {false, ?ERRCODE(err601_no_guild)};
        OpTy>0 andalso IsCd ->
            {false, ?ERRCODE(err610_is_cd)};
        true->
            Guild = mod_guild:get_guild_data(GuildId, all),
            GuildInfo = guild_to_cgw_guild_info(Guild),
            ServerId = config:get_server_id(),
            RoleInfo = #cgw_role_info{
                role_id = RoleId, name = RoleName, power = Power
                ,position = Position, lev = Lev, vip = Vip
                ,server_id = ServerId,sex = Sex, sup_vip = SVip
            },
            Msg = {sign_up, OpTy,Sid, RoleInfo, GuildInfo},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end.


%% ---------------------------------------------------------------------------
%% @doc 帮派数据转化为帮派报名信息。
-spec guild_to_cgw_guild_info(Guild) -> GuildInfo when
    Guild       :: #guild{},
    GuildInfo   :: #cgw_guild_info{}.
%% ---------------------------------------------------------------------------
guild_to_cgw_guild_info(Guild) ->
    #guild{
        id = GuildId, name = GuildName
        ,chief_id = ChiefId,combat_power = GuildPower
    } = Guild,
    ServerId = config:get_server_id(),
    ServerNum = config:get_server_num(),
    #figure{
        power = ChiefPower, name = ChiefName
    } = lib_role:get_role_figure(ChiefId),
    #cgw_guild_info{
        guild_id = GuildId, server_id = ServerId
        ,guild_name = GuildName, guild_power = GuildPower
        ,chief_id = ChiefId, chief_name = ChiefName, chief_power = ChiefPower
        ,server_num = ServerNum
    }.


%% ---------------------------------------------------------------------------
%% @doc 进入场景
-spec enter_scene(Role) -> {false, Reason} | ok when
    Role        :: #player_status{},
    Reason      :: integer().
%% ---------------------------------------------------------------------------
enter_scene(Role) ->
    #player_status{
        id = RoleId, guild = GuildStatus, combat_power = Power
        ,figure = Figure, sid = Sid, scene = Scene
    } = Role,
    #figure{
        name = RoleName, position = Position, lv= Lev, vip = Vip
    } = Figure,
    #status_guild{id = GuildId} = GuildStatus,
    SceneId = data_cross_guild_war:get_config(scene_id),
    {IsTransferable, ErrCode} = lib_scene:is_transferable(Role),
    CurS = cross_guild_war_local:get_local_state(),
    if
        CurS /= ?CGW_ST_PK ->
            {false, ?ERRCODE(err601_cant_enter_now)};
        GuildId =< 0 ->
            {false, ?ERRCODE(err601_no_guild)};
        Scene =:= SceneId ->
            {false, ?ERRCODE(err601_no_repeate_enter)};
        not IsTransferable ->
            {false, ErrCode};
        true ->
            ServerId = config:get_server_id(),
            RoleInfo = #cgw_role_info{
                role_id = RoleId, name = RoleName, power = Power
                ,position = Position, lev = Lev, vip = Vip
                ,server_id = ServerId
            },
            Msg = {enter_scene, Sid, RoleInfo},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end.

hosting_enter_scene(Role) ->
    #player_status{
        id = RoleId, combat_power = Power
        ,figure = Figure, sid = Sid
    } = Role,
    #figure{
        name = RoleName, position = Position, lv= Lev, vip = Vip
    } = Figure,
    ServerId = config:get_server_id(),
    RoleInfo = #cgw_role_info{
        role_id = RoleId, name = RoleName, power = Power
        ,position = Position, lev = Lev, vip = Vip
        ,server_id = ServerId
    },
    Msg = {enter_scene, Sid, RoleInfo},
    clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
    ok.


%% ---------------------------------------------------------------------------
%% @doc 进入跨服帮战场景
enter_scene_function(RoleId, PoolId, CopyId, X, Y, Group, GroupsBin) ->
    SceneId = data_cross_guild_war:get_config(scene_id),
    Args = [
        {group, Group}, {change_scene_hp_lim, 1}
        ,{action_lock, ?ERRCODE(err601_cant_change_scene_cross_gwar)}
        ,{erase_scene_pid, {SceneId, PoolId}}
    ],
    lib_scene:change_player_scene(
        RoleId, SceneId, PoolId, CopyId, X, Y, false, Args
    ),
    lib_achievement_api:async_event(RoleId, lib_achievement_api, cross_country_war_event, 1),
    lib_server_send:send_to_uid(RoleId, GroupsBin),
    lib_activity_reserve:enter_act(RoleId, ?MOD_CGWAR),
    ok.

%参与日志
add_log(RoleId,RName,GuildId,Power,Filed)->
    case czone_api:env_get_zone() of
        #czone_svr_local{zone_id = Zone,stage = Stage}->
            skip;
        _->
            Zone = 0,Stage=0
    end,
    lib_log_api:log_cross_guild_war(Zone,RoleId,RName,GuildId,Stage,Power,Filed).

log_cross_guild_war_conquer(RoleId,Name,CityId,GuildInfo)->
    #cgw_guild_info{
        zone_id = Zone,
        server_id=SerId,
        server_num = SerNum,
        guild_id = GuildId,
        chief_id=ChiefId
    } = GuildInfo,
    IsLord = case RoleId =:= ChiefId of
        true->
            1;
        _->
            0
    end,
    lib_log_api:log_cross_guild_war_conquer(Zone,SerId,SerNum,RoleId,Name,GuildId,IsLord,CityId).

log_cross_guild_war_support(RoleId,Name,RTimes,SerId,SerNum,CostList,Guild)->
     #cgw_guild_info{
        zone_id = Zone,
        guild_id = GuildId,
        guild_name = GName
    } = Guild,
    lib_log_api:log_cross_guild_war_support(Zone,SerId,SerNum,RoleId,Name,GuildId,GName,CostList,RTimes).


%% ---------------------------------------------------------------------------
%% @doc 退出场景
-spec leave_scene(Role) -> {false, Reason} | ok when
    Role        :: #player_status{},
    Reason      :: integer().
%% ---------------------------------------------------------------------------
leave_scene(Role) ->
    #player_status{
        id = RoleId, guild = GuildStatus, sid = Sid, scene = Scene
    } = Role,
    #status_guild{id = GuildId} = GuildStatus,
    SceneId = data_cross_guild_war:get_config(scene_id),
    ServerId = config:get_server_id(),
    if
        GuildId =< 0 ->
            {false, ?ERRCODE(err601_no_guild)};
        Scene =/= SceneId ->
            {false, ?ERRCODE(err601_not_in_cgw_scene)};
        true ->
            Msg = {leave_scene, Sid, RoleId, ServerId},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end.


%% ---------------------------------------------------------------------------
%% @doc 离开跨服帮战场景
-spec leave_scene_function(RoleId) -> ok when
    RoleId      :: integer().
%% ---------------------------------------------------------------------------
leave_scene_function(RoleId) ->
    Args = [
        {action_free, ?ERRCODE(err601_cant_change_scene_cross_gwar)}
        ,{change_scene_hp_lim, 1}, {group, 0}
    ],
    lib_scene:change_player_scene(RoleId, 0, 0, 0, 0, 0, true, Args),
    cross_point_fight_local:remove_buff(RoleId),
    ok.


%% ---------------------------------------------------------------------------
%% @doc 战场信息
-spec send_battlefield_info(Role) -> ok when
    Role        :: #player_status{}.
%% ---------------------------------------------------------------------------
send_battlefield_info(Role) ->
    #player_status{guild = GuildStatus, sid = Sid, scene = Scene, id = RoleId} = Role,
    #status_guild{id = _GuildId} = GuildStatus,
    SceneId = data_cross_guild_war:get_config(scene_id),
    if
        Scene =/= SceneId ->
            ok;
        true ->
            ServerId = config:get_server_id(),
            Msg = {send_battlefield_info, Sid, RoleId, ServerId},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end.


%% ---------------------------------------------------------------------------
%% @doc 合服处理
-spec merge_server(ServerId, MergeIdList) -> ok when
    ServerId    :: integer(),
    MergeIdList :: [ServerId].
%% ---------------------------------------------------------------------------
merge_server(ServerId, MergeIdList) ->
    cross_guild_war_mgr:cast({merge_server, ServerId, MergeIdList}),
    ok.


%% ---------------------------------------------------------------------------
%% @doc 发出号令
-spec send_guild_direction(Role, CityId) -> ok when
    Role        :: #player_status{},
    CityId      :: integer().
%% ---------------------------------------------------------------------------
send_guild_direction(Role, CityId) ->
    #player_status{guild = GuildStatus, sid = Sid, scene = Scene,id = RoleId} = Role,
    #status_guild{id = GuildId, position = Position} = GuildStatus,
    SceneId = data_cross_guild_war:get_config(scene_id),
    IsPermission = lists:member(Position, [?POS_CHIEF, ?POS_DUPTY_CHIEF]),
    IsCity = lists:member(CityId, data_cross_guild_war:city_ids()),
    Result = if
        GuildId =< 0 ->
            ok;
        Scene =/= SceneId ->
            ok;
        not IsPermission ->
            {false, ?ERRCODE(err601_no_permission)};
        not IsCity ->
            {false, ?ERRCODE(err601_not_city)};
        true ->
            ServerId = config:get_server_id(),
            Msg = {send_guild_direction, Sid, RoleId, ServerId, CityId},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end,
    case Result of
        {false, Reason} ->
            {ok, BinData} = pt_601:write(60112, [Reason]),
            lib_server_send:send_to_sid(Sid, BinData);
        _ ->
            ok
    end,
    ok.


%% ---------------------------------------------------------------------------
%% @doc 应援帮派
-spec support_guild(Role, ServerId, GuildId) ->
    {false, Reason} | {ok, NewRole} when
    Role        :: #player_status{},
    ServerId    :: integer(),
    GuildId     :: integer(),
    Reason      :: integer(),
    NewRole     :: #player_status{}.
%% ---------------------------------------------------------------------------
support_guild(Role, ServerId, GuildId) ->
    #player_status{sid = Sid, id = RoleId, pid = Pid} = Role,
    #role_cgw{
        support_num = SupportNum, use_free_num = UseFreeNum
    } = get_role_cgw(Role),
    SupportServerId = config:get_server_id(),
    SupportRole = #cgw_support{
        role_id = RoleId, server_id = SupportServerId, num = 1
    },
    VipT = lib_vip_api:get_vip_privilege(Role,?MOD_CGWAR, 1),
    MaxNum = data_cross_guild_war:get_config(support_max)+VipT,
    FreeTimes = data_cross_guild_war:get_config(support_free),
    CostList = case UseFreeNum >= FreeTimes of
        true -> data_cross_guild_war:get_config(support_cost);
        false -> []
    end,
    IsEnough = lib_goods_api:check_object_list(Role, CostList),
    CurS = cross_guild_war_local:get_local_state(),
    IsSupport = lists:member(CurS,[?CGW_ST_SIGN,?CGW_ST_SUPPORT]),
    if
        SupportNum >= MaxNum ->
            {false, ?ERRCODE(err601_support_max)};
        IsEnough =/= true ->
            IsEnough;
        not IsSupport ->
             {false, ?ERRCODE(err601_support_time)};
        true ->
            Msg = {support, SupportRole, ServerId, GuildId, Sid, Pid},
            clusters_node:apply_cast({cross_guild_war_mgr, cast, [Msg]}),
            {ok, Role}
    end.

%% 获取角色跨服帮战应援和领取奖励记录
get_role_cgw(#player_status{cross_guild_war = RoleCgw}) ->
    #role_cgw{
        support_time = SupportTime, award_time = AwardTime
    } = RoleCgw,
    NowTime = utime:unixtime(),
    RoleCgw2 = case utime:is_same_day(NowTime, SupportTime) of
        true -> RoleCgw;
        false -> RoleCgw#role_cgw{support_num = 0, use_free_num = 0}
    end,
    RoleCgw3 = case utime:is_same_day(NowTime, AwardTime) of
        true -> RoleCgw2;
        false -> RoleCgw2#role_cgw{city_award = []}
    end,
    RoleCgw3.


%% ---------------------------------------------------------------------------
%% @doc 应援帮派callback
-spec support_guild_callback(Role) -> {false, Reason} | {ok, NewRole} when
    Role        :: #player_status{},
    Reason      :: integer(),
    NewRole     :: #player_status{}.
%% ---------------------------------------------------------------------------
support_guild_callback(Role) ->
    RoleCgw = #role_cgw{
        support_num = SupportNum, use_free_num = UseFreeNum
    } = get_role_cgw(Role),
    #player_status{
        id = RoleId,
        figure = Figure,
        server_id=SerId,
        server_num=SerNum
    } = Role,
    #figure{ name = Name} = Figure,
    FreeTimes = data_cross_guild_war:get_config(support_free),
    MaxTimes  = data_cross_guild_war:get_config(support_max),
    {CostList, NewUseFreeNum} = case UseFreeNum >= FreeTimes of
        true ->
            {data_cross_guild_war:get_config(support_cost), UseFreeNum};
        false ->
            {[], UseFreeNum + 1}
    end,
    case lib_goods_api:cost_object_list_with_check(
            Role, CostList, cross_guild_war_support, ""
        ) of
        {false, ErrorCode, _Role2} ->
            {{false, ErrorCode}, Role};
        {true, Role2, _} ->
            NewRoleCgw = RoleCgw#role_cgw{
                support_num = SupportNum + 1, use_free_num = NewUseFreeNum
                ,support_time = utime:unixtime()
            },
            case SupportNum + 1 of
                10 ->
                    lib_chat:send_TV({all}, ?MOD_CGWAR, 5, [Name]);
                _ ->
                    ok
            end,
            cross_guild_war_db:save_role_cgw(RoleId, NewRoleCgw),
            NewRole = Role2#player_status{cross_guild_war = NewRoleCgw},
            RTimes = max(MaxTimes-SupportNum-1,0),
            Reply  = {Name,RTimes,SerId,SerNum,CostList},
            {{ok,Reply}, NewRole}
    end.


%% ---------------------------------------------------------------------------
%% @doc 应援列表
send_support_list(Role) ->
    #player_status{id = RoleId, sid = Sid} = Role,
    #role_cgw{
        support_num = SupportNum, use_free_num = UseFreeNum
    } = get_role_cgw(Role),
    FreeTimes = data_cross_guild_war:get_config(support_free),
    LessFreeTimes = max(0, FreeTimes - UseFreeNum),
    ServerId = config:get_server_id(),
    Msg = {
        send_support_list, ServerId, Sid, SupportNum
        ,LessFreeTimes, RoleId
    },
    clusters_node:apply_cast({cross_guild_war_mgr, cast, [Msg]}).


%% @doc 领取占领城池奖励
get_city_award(Role, CityId) ->
    #player_status{sid = Sid, pid = Pid, guild = GuildStatus} = Role,
    #role_cgw{city_award = AwardLog} = get_role_cgw(Role),
    ServerId = config:get_server_id(),
    #status_guild{id = GuildId} = GuildStatus,
    HaveGet = lists:member(CityId, AwardLog),
    if
        GuildId =< 0 ->
            {false, ?ERRCODE(err601_no_guild)};
        HaveGet ->
            {false, ?ERRCODE(err601_cant_repeate_get_award)};
        true ->
            Msg = {get_city_award, ServerId, CityId, GuildId, Sid, Pid},
            clusters_node:apply_cast({cross_guild_war_mgr, cast, [Msg]}),
            ok
    end.


%% ---------------------------------------------------------------------------
%% @doc 领取占领城池奖励
get_city_award_callback(Role, CityId) ->
    #player_status{sid = Sid, id = RoleId} = Role,
    RoleCgw = #role_cgw{city_award = AwardLog} = get_role_cgw(Role),
    Award = case data_cross_guild_war:get_city_config(CityId) of
        #cross_guild_war_city{type_id = ?CITY_TYPE_MAIN} ->
            data_cross_guild_war:get_config(centerfield_daily_award);
        _ ->
            data_cross_guild_war:get_config(surroundfield_daily_award)
    end,
    Produce = #produce{
        reward = Award, type = cross_guild_war_city_daily_award, show_tips = 1
    },
    {NewRole, ErrCode} = case lib_goods_api:can_give_goods(Role,Award) of
        true ->
            NewAwardLog = [CityId | AwardLog],
            NewRoleCgw = RoleCgw#role_cgw{
                city_award = NewAwardLog, award_time = utime:unixtime()
            },
            cross_guild_war_db:save_role_cgw(RoleId, NewRoleCgw),
            Role2 = Role#player_status{cross_guild_war = NewRoleCgw},
            %% 发奖励
            Role3 = lib_goods_api:send_reward(Role2, Produce),
            {Role3, ?SUCCESS};
        _ ->
            {Role, ?ERRCODE(err150_no_cell)}
    end,
    {ok, BinData} = pt_601:write(60107, [CityId, ErrCode]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, NewRole}.


%% ---------------------------------------------------------------------------
%% @doc 上次活动中城池占领信息
-spec send_city_info(Role) -> ok when
    Role    :: #player_status{}.
%% ---------------------------------------------------------------------------
send_city_info(Role) ->
    #player_status{sid = Sid} = Role,
    #role_cgw{city_award = AwardLog} = get_role_cgw(Role),
    ServerId = config:get_server_id(),
    Msg = {send_city_info, ServerId, Sid, AwardLog},
    MFA = {cross_guild_war_mgr, cast, [Msg]},
    clusters_node:apply_cast(MFA),
    ok.


%% ---------------------------------------------------------------------------
%% @doc 活动结束清除玩家应援和领取奖励记录
-spec del_role_cgw() -> ok.
%% ---------------------------------------------------------------------------
del_role_cgw() ->
    cross_guild_war_db:del_role_cgw(),
    Pids = lib_player:get_online_pids(),
    [
        lib_player:apply_cast(
            Pid, ?APPLY_CAST_SAVE, cross_guild_war_api, reset_role_cgw, []
        ) || Pid <- Pids
    ],
    ok.


%% ---------------------------------------------------------------------------
%% @doc 重置玩家应援和领取奖励记录
-spec reset_role_cgw(Role) -> {ok, NewRole} when
    Role        :: #player_status{},
    NewRole     :: #player_status{}.
%% ---------------------------------------------------------------------------
reset_role_cgw(Role) ->
    NewRole = Role#player_status{cross_guild_war = #role_cgw{}},
    {ok, NewRole}.

mark_sign_cancle(Role)->
    #player_status{id=RoleId,cross_guild_war=RoleCgw}=Role,
    Now = utime:unixtime(),
    NewRoleCgw = RoleCgw#role_cgw{last_sign=Now},
    NewRole = Role#player_status{cross_guild_war = NewRoleCgw},
    cross_guild_war_db:save_role_cgw(RoleId, NewRoleCgw),
    {ok,NewRole}.

%% ---------------------------------------------------------------------------
%% @doc 获取复活坐标
get_born_xy(BattlePid, Group, Scene) ->
    try cross_guild_war_battle:call(BattlePid, {get_born_xy, Group}) of
        {0, 0} -> {Scene#ets_scene.x, Scene#ets_scene.y};
        {X, Y} when is_integer(X) andalso is_integer(Y) -> {X, Y};
        _ -> {Scene#ets_scene.x, Scene#ets_scene.y}
    catch
        _:_ ->
            {Scene#ets_scene.x, Scene#ets_scene.y}
    end.

get_revive_xy(BattlePid,Group,Scene)->
    try cross_guild_war_battle:call(BattlePid, {get_revive_xy, Group}) of
        {0, 0} -> {Scene#ets_scene.x, Scene#ets_scene.y};
        {X, Y} when is_integer(X) andalso is_integer(Y) -> {X, Y};
        _ -> {Scene#ets_scene.x, Scene#ets_scene.y}
    catch
        _:_ ->
            {Scene#ets_scene.x, Scene#ets_scene.y}
    end.

get_battle_xy(BattlePid,Group,Scene)->
    try cross_guild_war_battle:call(BattlePid, {get_battle_xy, Group}) of
        {0, 0} -> {Scene#ets_scene.x, Scene#ets_scene.y};
        {X, Y} when is_integer(X) andalso is_integer(Y) -> {X, Y};
        _ -> {Scene#ets_scene.x, Scene#ets_scene.y}
    catch
        _:_ ->
            {Scene#ets_scene.x, Scene#ets_scene.y}
    end.


%% ---------------------------------------------------------------------------
%% @doc 客户端断开连接或者角色进程退出
handle_event(Player, #event_callback{type_id = ?EVENT_DISCONNECT}) ->
    cross_guild_war_api:leave_scene(Player),
    {ok, Player};
handle_event(Player, #event_callback{type_id = ?EVENT_FIN_CHANGE_SCENE})->
    #player_status{
        id = RoleId,
        scene = Scene
    } = Player,
    case Scene == data_cross_guild_war:get_config(scene_id) of
        true->
            cross_point_fight_local:add_buff(RoleId);
        _->
            skip
    end,
    {ok,Player};
handle_event(Player, _) ->
    {ok, Player}.

%%测试增加社团
gm(RoleID)->
    lib_player:apply_cast(RoleID, ?APPLY_CAST_SAVE, ?MODULE, gm_guild, []).
gm_guild(Status)->
    #player_status{
        guild = GuildStatus
    } = Status,
    #status_guild{id = GuildId} = GuildStatus,
    Guild = mod_guild:get_guild_data(GuildId, all),
    GuildInfo = guild_to_cgw_guild_info(Guild),
    #czone_svr_local{zone_id=ZoneId} = czone_api:env_get_zone(),
    FactId = czone_api:env_get_faction(),
    clusters_node:apply_cast({cross_guild_war_mgr,update_join_guild,[ZoneId,FactId,[GuildInfo#cgw_guild_info{zone_id = ZoneId,fact_id = FactId}]]}),
    Status.

%% ----------------------------------霸主特权-----------------------------------------
load_overlord_info(RoleId) ->
    case db:get_all(io_lib:format(?SQL_SELECT_OVERLORD, [RoleId])) of
        [[Times, ProTime, RenameList, BuyTime]] ->
            #overlord_info{prohibit_times = Times, pro_time = ProTime,  rename_time =  util:bitstring_to_term(RenameList), buy_time = BuyTime};
        _ ->
            undefined
    end.

%% 禁言
prohibit_talk(Player, OtherRoleId) ->
    #player_status{id = RoleId, server_id = ServerId, figure = Figure, overlord_privilege = OverlordData} = Player,
    #figure{king = King} = Figure,
    {Times, #overlord_info{pro_time = ProTime, prohibit_times = NewTimes, rename_time = RenameList, buy_time = BuyTime} = NewOverlordData}
        = get_prohibit_times(OverlordData),
    <<OtherServerId:16, _:32>> =  <<OtherRoleId:48>>,
    if
        King == 1 andalso Times < 2 ->
            ZoneId = clusters_node:apply_call(cross_zone, get_server_zone, [czone, ServerId]),
            ZoneId2 = clusters_node:apply_call(cross_zone, get_server_zone, [czone, OtherServerId]),

            if
                ZoneId == ZoneId2 ->
                    if
                        ServerId == OtherServerId -> lib_chat:forbid_chat([OtherRoleId], 4, ?TALK_LIMIT_TYPE_6);
                        true ->
                            clusters_node:apply_cast(clusters_center, apply_cast,
                                [OtherServerId,{lib_chat, forbid_chat, [[OtherRoleId], 4, ?TALK_LIMIT_TYPE_6]}])
                    end,
                    db:execute(io_lib:format(?SQL_REPLACE_OVERLORD, [RoleId, NewTimes, ProTime, util:term_to_bitstring(RenameList), BuyTime])),
                    NewPlayer = Player #player_status{overlord_privilege = NewOverlordData},
                    {ok, NewPlayer};
                true ->
                    {false, ?FAIL}
            end;
        King == 1 -> {false, ?ERRCODE(err601_exceed_times)};
        true -> {false, ?ERRCODE(err601_not_king)}
    end.

%% 获取今日禁言使用次数
get_prohibit_times(OverlordData) ->
    Data =
        if
            is_record(OverlordData, overlord_info) -> OverlordData;
            true -> #overlord_info{}
        end,
    #overlord_info{pro_time = LastTime, prohibit_times = Times} = Data,
    NowTime = utime:unixdate(),
    IsSame = utime:is_same_day(LastTime, NowTime),
    if
        IsSame -> {Times, Data#overlord_info{pro_time = NowTime, prohibit_times = Times + 1}};
        true -> {0, Data#overlord_info{pro_time = NowTime, prohibit_times = 1}}
    end.

%% 国家改名
faction_rename(Player, FactId, FactionName) ->
    #player_status{id = RoleId, server_id = ServerId, figure = Figure, overlord_privilege = OverlordData} = Player,
    #figure{king = King} = Figure,
    Data =
        if
            is_record(OverlordData, overlord_info) -> OverlordData;
            true -> #overlord_info{}
        end,
    #overlord_info{rename_time = RenameList} = Data,
    case lists:keyfind(FactId, 1,RenameList) of
        {_, Time} -> skip;
        _ -> Time = 0
    end,
    NowTime = utime:unixdate(),
    % 改名CD为72h
    CanRename = ?IF(NowTime > Time + 60 * 60 * 72, true, false),
    IsTrue = check_length(FactionName),
    IsKeyWord = lib_word:check_keyword(FactionName),
    if
        FactionName == "" -> {false, ?ERRCODE(err601_faction_name_null)};
        IsKeyWord -> {false, ?ERRCODE(err601_faction_name_sensitive)};
        not IsTrue -> {false, ?ERRCODE(err601_faction_name_len)};
        King =/= 1 -> {false, ?ERRCODE(err601_not_king)};
        not CanRename -> {false, ?ERRCODE(err601_not_enough_cd)};
        true ->
            Msg = {faction_rename, RoleId, ServerId, FactId, FactionName},
            clusters_node:apply_cast(cross_guild_war_mgr, cast, [Msg]),
            ok
    end.

check_length(FactionName) ->
    case unicode:characters_to_list(FactionName) of
        {incomplete, _Encoded, _Rest} ->
            false;
        {error, _Encoded, _Rest} ->
            false;
        UnicodeList ->
            Len = length(UnicodeList),
            % 国家名2-4个字
            2 =< Len andalso Len =< 4
    end.

rename_callback(Player, ErrCode, FactId, FactionName) ->
    #player_status{id = RoleId, sid = Sid, overlord_privilege = OverlordData} = Player,
    if
        ErrCode =:= 1 ->
            NowTime = utime:unixtime(),
            Data =
                if
                    is_record(OverlordData, overlord_info) -> OverlordData;
                    true -> #overlord_info{}
                end,
            #overlord_info{prohibit_times = Times, pro_time = ProTime, buy_time = BuyTime, rename_time = RenameList} = Data,




            NewList = lists:keystore(FactId, 1, RenameList, {FactId, NowTime}),
            db:execute(io_lib:format(?SQL_REPLACE_OVERLORD, [RoleId, Times, ProTime, util:term_to_bitstring(NewList), BuyTime])),
            NewOverlordData = Data#overlord_info{rename_time = NewList},
            NewPlayer = Player#player_status{overlord_privilege = NewOverlordData};
        true ->
            NewPlayer = Player
    end,
    {ok, BinData} = pt_601:write(60121, [ErrCode, FactId, FactionName]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, NewPlayer}.

%% 霸主限购-物品信息
get_goods_info(Player) ->
    #player_status{sid = Sid, figure = Figure, overlord_privilege = OverlordData} = Player,
    #figure{king = King} = Figure,
    case OverlordData of
        #overlord_info{buy_time = BuyTime} -> skip;
        _ -> BuyTime = 0
    end,
    {IsBuy, BuyCfg} = get_buy_cfg(BuyTime),
    CanBuy = ?IF(King == 1, IsBuy, 0),
    if
        is_record(BuyCfg, overlord_buy_cfg) ->
            ErrCode = ?SUCCESS,
            #overlord_buy_cfg{reward = Rewards, cost = Cost, display = Display} = BuyCfg;
        true ->
            Display = 0,
            Rewards = Cost =[],
            ErrCode = ?ERRCODE(missing_config)
    end,
    {ok, BinData} = pt_601:write(60122, [ErrCode, CanBuy, Rewards, Cost, Display]),
    lib_server_send:send_to_sid(Sid, BinData).

%% 获取购买配置
get_buy_cfg(BuyTime) ->
    case data_cross_guild_war:get_config(open_time) of
        OpenTime when is_integer(OpenTime) ->
            % 固定一期为7天
            CycleTime = 86400 * 7,
            NowTime = utime:unixtime(),
            ContinuedTime = NowTime - OpenTime,
            Phase = ContinuedTime div CycleTime + 1,
            OldPhase = (BuyTime - OpenTime) div CycleTime + 1,
            case data_cross_guild_war:get_overlord_buy_cfg(Phase) of
                #overlord_buy_cfg{} = Config when Phase =/= OldPhase ->
                    {1, Config};
                #overlord_buy_cfg{} = Config ->
                    {0, Config};
                _ ->
                    {0, false}
            end;
        _ ->
            {0, false}
    end.

%% 霸主限购-购买
overlord_buy(Player) ->
    #player_status{id = RoleId, figure = Figure, overlord_privilege = OverlordData} = Player,
    #figure{king = King} = Figure,
    Data =
        case OverlordData of
            #overlord_info{buy_time = BuyTime} ->
                OverlordData;
            _ ->
                BuyTime = 0,
                #overlord_info{}
        end,
    {IsBuy, BuyCfg} = get_buy_cfg(BuyTime),
    if
        King =/= 1 ->
            {false, ?ERRCODE(err601_not_king)};
        BuyCfg == false ->
            {false, ?ERRCODE(missing_config)};
        IsBuy == 0 ->
            {false, ?ERRCODE(err601_cant_buy)};
        true ->
            #overlord_buy_cfg{reward = Rewards, cost = Cost} = BuyCfg,
            case lib_goods_api:cost_object_list_with_check(Player, Cost, overlord_buy, "") of
                {true, NewPlayer, _}  ->
                    NowTime = utime:unixtime(),
                    NOverlordData = Data#overlord_info{buy_time = NowTime},
                    #overlord_info{prohibit_times = Times, pro_time = ProTime, rename_time = RenameList} = NOverlordData,
                    db:execute(io_lib:format(?SQL_REPLACE_OVERLORD, [RoleId, Times, ProTime, util:term_to_bitstring(RenameList), NowTime])),
                    NewPlayer1 = NewPlayer#player_status{overlord_privilege = NOverlordData},
                    NewPlayer2 = lib_goods_api:send_reward(NewPlayer1, Rewards, overlord_buy),
                    {ok, NewPlayer2};
                {false, ErrCode, _} -> {false, ErrCode}
            end
    end.

%% 取消霸主身份
cancel_overlord() ->
    game_env:save(cgw_king, 0),
    game_env:save(quasi_cgw_king, []),
    db:execute(io_lib:format(?SQL_TRUNCATE_OVERLORD, [])),
    lib_player:cast_online_role_apply(?APPLY_CAST_SAVE, ?MODULE, do_cancel_overlord, []).

do_cancel_overlord(#player_status{figure = #figure{king = King}} = Status) when King == 1 orelse King == 2 ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Status,
    NFigure = Figure#figure{king = 0},
    NStatus = Status#player_status{figure = NFigure, overlord_privilege = undefined},
    mod_scene_agent:update(NStatus,[{cgw_king,0}]),
    lib_role:update_role_show(RoleId, [{figure, NFigure}]),
    {ok, BinData} = pt_601:write(60124, [0]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, NStatus};
do_cancel_overlord(Status) ->
    {ok, Status}.

%% 拼接怪物名字
get_mon_name(GuildName, MonId) ->
    case data_mon:get(MonId) of
        #mon{name = Name} -> ok;
        _ -> Name = "boss"
    end,
    if
        is_binary(GuildName) ->
            GuildNameL   = unicode:characters_to_list(GuildName),
            Name1       = unicode:characters_to_list("-"),
            Name2       = unicode:characters_to_list(Name),
            MonName     = GuildNameL ++ Name1 ++ Name2,
            MonName1    = unicode:characters_to_binary(MonName),
            MonName1;
        true ->
            MonName = unicode:characters_to_list(Name),
            MonName1    = unicode:characters_to_binary(MonName),
            MonName1
    end.


%% -----------------gm--------------------
%% 重置霸主限购次数和禁言次数
gm_reset_data(Status) ->
    #player_status{id = RoleId} = Status,
    db:execute(io_lib:format(?SQL_REPLACE_OVERLORD, [RoleId, 0, 0, util:term_to_bitstring([]), 0])),
    NewStatus = Status#player_status{overlord_privilege = #overlord_info{}},
    {ok, NewStatus}.