%%%-----------------------------------
%%% @Module  : lib_skill
%%% @Author  : zzm
%%% @Created : 2013.12.2
%%% @Description: 技能
%%%-----------------------------------
-module(lib_skill).
-include("common.hrl").
-include("server.hrl").
-include("skill.hrl").
-include("predefine.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("attr.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-include("def_fun.hrl").
-include("buff.hrl").
-include("scene.hrl").
-include("battle.hrl").
-include("def_goods.hrl").
-include("vip.hrl").

-export([
        get_skill_list/1,
        get_my_skill_list/1,
        get_all_skill/1,
        handle_event/2,
        create_role_full_skill/1,
        clear_role_full_skill/1,
        skill_online/5,
        send_my_skill_list/1,
        upgrade_skill/2,
        auto_learn_skill/2,
        add_tmp_skill_list/3,
        del_tmp_skill_list/2,
        get_normal_skill/1,
        get_ori_normal_skill/2,  %% 获取角色创建角色时候的普攻技能
        divide_passive_skill/1,
        divide_active_skill/1,
        count_skill_power/1,
        count_hp_resume_spcl_add/2,
        update_status_skill/5,
        update_skill_attribute_for_ps/1,
        calc_lv_times/2  %%计算升级次数
    ]).

-export([
        get_talent_skill_type_info/1,
        check_talent_skill_learn/6,
        get_talent_type_use_point/2,
        give_def_talent_skill_point/1,
        learn_talent_skill/2,
        reset_talent_skill/1,
        reset_talent_skill_core/1,
        trigger_talent_active/4,
        get_talent_active_info/3
    ]).

%% for debug
-export([
        debug_check_hp_resume/1
    ]).

%% 职业主动技能列表(ID从小到大排序, 共5个)
get_skill_list(?SWORDSMAN) ->
    [{1, 101001}, {2, 101011}, {3, 101021}, {4, 101031}, {5, 101041}];
get_skill_list(?KNIGHT) ->
    [{1, 102001}, {2, 102011}, {3, 102021}, {4, 102031}, {5, 102041}];
get_skill_list(?MAGE) ->
    [{1, 103001}, {2, 103011}, {3, 103021}, {4, 103031}, {5, 103041}];
get_skill_list(?GUNNER) ->
    [{1, 104001}, {2, 104011}, {3, 104021}, {4, 104031}, {5, 104041}].

%% 处理玩家升级事件
handle_event(PS, #event_callback{type_id = ?EVENT_LV_UP_BF_COUNT_ATTR}) ->
    #player_status{figure=#figure{lv=Lv}} = PS,
    {ok, NewPS} = auto_learn_skill(PS, {lv, Lv}),
    update_spcl_attr_with_lv_up(NewPS);
%% vip激活和升级事件
handle_event(PS, #event_callback{type_id = ?EVENT_VIP}) ->
    {VipType, RealLv, TrialLv} = lib_vip_api:get_valid_vip_lv(PS),
    VipLev =
    if VipType == ?VIP_NORMAL -> RealLv;
        true -> TrialLv
    end,
    auto_learn_skill(PS, {vip, VipLev});
%% 体验VIP过期
handle_event(PS, #event_callback{type_id = ?EVENT_VIP_TIME_OUT}) when is_record(PS, player_status) ->
    #player_status{id = RoleId, sid = Sid, quickbar = OldQuickbar} = PS,
    TimeOutPS = check_del_skill(PS, {vip_time_out}),
    NewPS = #player_status{quickbar = NewQuickbar} = quickbar_api:check_fill_quickbar(TimeOutPS),
    case quickbar_api:check_equal(NewQuickbar, OldQuickbar) of
        true  -> ignore;
        false ->
            quickbar_api:db_save_quickbar(RoleId, NewQuickbar),
            quickbar_api:notice_quickbar(Sid, NewQuickbar)
    end,
    {ok, NewPS};
handle_event(PS, #event_callback{type_id = ?EVENT_CLIENT_LOGIN_SUCCESS}) ->
    #player_status{figure = Figure, skill = StatusSkill, vip_status = RoleVip} = PS,
    #status_skill{skill_list = AllSkillList} = StatusSkill,
    OtherActiveSkill = lists:seq(109001, 109008),
    SpecSkill =  [101091, 102091, 103091, 104091, 109100, 109101, 120001, 120002, 120003],
    handle_active_skill(PS, Figure#figure.career, AllSkillList, OtherActiveSkill, SpecSkill),
    #vip_status{sup_vip = SupVip} = RoleVip,
    VipSkills = case SupVip#role_sup_vip.type > 0 of
                    true -> [{109101, 1}];
                    _ -> []
                end,
    VisusSkills = lib_role_visus:get_skills(PS),
    handle_spec_skill(PS, lists:ukeysort(1, AllSkillList ++ VipSkills ++ VisusSkills), SpecSkill),
    {ok, PS};
handle_event(PS, _) -> {ok, PS}.

%% 增加临时技能
add_tmp_skill_list(PS, SkillId, SkillLv) ->
    #player_status{skill=Skill} = PS,
    {ok, PS#player_status{skill=Skill#status_skill{tmp_skill_list=[{SkillId, SkillLv}|Skill#status_skill.tmp_skill_list]}}}.

%% 移除临时技能
del_tmp_skill_list(PS, SkillId) ->
    #player_status{skill=Skill} = PS,
    {ok, PS#player_status{skill=Skill#status_skill{tmp_skill_list=lists:keydelete(SkillId, 1, Skill#status_skill.tmp_skill_list)}}}.

%% 创建角色时给满技能(测试时期暂时去掉)
%% create_role_full_skill(PS) ->
%%     StatusSkill = PS#player_status.skill,
%%     Skills = data_skill:get_ids(PS#player_status.figure#figure.career),
%%     F = fun({SkillId, MaxLv}, List) ->
%%             case data_skill:get(SkillId, MaxLv) of
%%                 #skill{type=Type, is_combo=0} when Type == ?SKILL_TYPE_ACTIVE orelse Type == ?SKILL_TYPE_ASSIST ->
%%                     [{SkillId, MaxLv}|List];
%%                 _ -> List
%%             end
%%     end,
%%     SkillList = lists:foldl(F, [], Skills),
%%     PS#player_status{skill=StatusSkill#status_skill{skill_list=SkillList}}.

create_role_full_skill(PS) ->
    #player_status{skill = StatusSkill, figure = Figure} = PS,
    Skills = lib_skill_api:get_career_skill_ids(Figure#figure.career, Figure#figure.sex),
    F = fun({SkillId, MaxLv}, List) ->
                case data_skill:get(SkillId, MaxLv) of
                    #skill{type=Type, is_combo=0, lv_data = LvData}
                      when (Type == ?SKILL_TYPE_ACTIVE orelse Type == ?SKILL_TYPE_ASSIST) andalso LvData#skill_lv.condition == [] ->
                        [{SkillId, MaxLv}|List];
                    _ -> List
                end
        end,
    SkillList = lists:foldl(F, [], Skills),
    PS#player_status{skill=StatusSkill#status_skill{skill_list=SkillList}}.

%% 重新整理角色技能(读取数据库，谨慎使用)
clear_role_full_skill(#player_status{id=Id, skill=Sk} = PS) ->
    SkillList = get_all_skill(Id),
    PS#player_status{skill=Sk#status_skill{skill_list=SkillList}}.

%% 玩家登录加载技能数据
skill_online(RoleId, Career, Lv, AllPoint, {VipType, VipLv, TrialLv}) ->
    %% 职业技能初始化
    SkillList0 = get_all_skill(RoleId),
    SkillList  = filter_vip_expire_skill(SkillList0, RoleId, Career, {VipType, VipLv, TrialLv}),
    {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(SkillList, Lv),
    HpResumeSpclAdd = count_hp_resume_spcl_add(Lv, SkillList),
    CarreerSkillStatus = #status_skill{
        skill_list = SkillList,
        skill_passive = divide_passive_skill(SkillList),
        skill_attr = SkillAttr, skill_power = SkillPower
        %% skill_attr_other = SkillAttrOhter
        ,hp_resume_spcl_add = HpResumeSpclAdd
    },
    %% 天赋技能初始化
    SkillTalentList = get_all_talent_skill(RoleId),
    {UsePoint, SkillTalentPower, _L} = get_talent_skill_type_info(SkillTalentList),
    %% {SkillTalentAttr, SkillTalentAttrOhter} = lib_skill_attr:get_passive_skill_attr(SkillTalentList, Lv),
    SkillTalentAttr = lib_skill_attr:get_passive_skill_attr(SkillTalentList, Lv),
    TalentSkillStatus = CarreerSkillStatus#status_skill{
        skill_talent_list = SkillTalentList,
        skill_talent_passive = divide_passive_skill(SkillTalentList),
        skill_talent_active_list = divide_active_skill(SkillTalentList),
        skill_talent_attr = SkillTalentAttr,
        %% skill_talent_attr_other = SkillTalentAttrOhter,
        point = AllPoint,
        skill_talent_power = SkillTalentPower,
        use_point = UsePoint
    },
    TalentSkillStatus.

%% 发送技能列表
send_my_skill_list(PS) ->
    PackList = get_my_skill_list(PS),
    {ok, BinData} = pt_210:write(21002, [PackList]),
    lib_server_send:send_to_sid(PS#player_status.sid, BinData).

get_my_skill_list(PS) ->
    #player_status{figure = Figure, skill = Sk, passive_skills = PassiveSkill} = PS,
    #figure{career = Career, sex = Sex} = Figure,
    Skills = lib_skill_api:get_career_all_skill_ids2(Career, Sex),
    F = fun({SkillId, MaxLv}, TmpSkillList) ->
        case data_skill:get(SkillId, MaxLv) of
            #skill{} ->
                case lists:keyfind(SkillId, 1, Sk#status_skill.skill_list) of
                    false -> TmpSkillList;
                    {_, SkillLv} -> [{SkillId, SkillLv} | TmpSkillList]
                end;
            _ -> TmpSkillList
        end
    end,
    SkillL1 = lists:foldl(F, [], Skills),
    SkillL2 = case lists:keyfind(?SUPVIP_FORBID_JUMP_SKILL, 1, PassiveSkill) of
        {SkillId, SkLv} -> [{SkillId, SkLv}];
        _               -> []
    end,
    SkillL2 ++ SkillL1.

filter_auto_learn_skill(Career, Sex, Event) ->
    case Event of
        login ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = skip;
        {lv, RoleLv} ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = fun(T) ->
                case T of
                    {lv, TRoleLv} when TRoleLv =/= RoleLv -> false;
                    _ -> true
                end
            end;
        {finish_dun, DunId} ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = fun(T) ->
                case T of
                    {finish_dun, TDunId} when TDunId =/= DunId -> false;
                    _ -> true
                end
            end;
        {turn, Turn, _ReSkillList} ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = fun(T) ->
                case T of
                    {turn, TTurn} when TTurn =/= Turn -> false;
                    _ -> true
                end
            end;
        {transfer, _ReSkillList} ->
            SkillIds = lib_skill_api:get_career_skill_ids(Career, Sex),
            FilterF = skip;
        {task, TaskId} ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = fun(T) ->
                case T of
                    {task, FinishTaskId} when FinishTaskId =/= TaskId -> false;
                    _ -> true
                end
            end;
        {vip, VipLev} ->
            SkillIds = lib_skill_api:get_career_all_skill_ids(Career, Sex),
            FilterF = fun(T) ->
                    case T of
                        {vip, TVipLev} when TVipLev > VipLev -> false;
                        _ -> true
                    end
            end;
        _ -> SkillIds = [], FilterF = skip
    end,
    F = fun({SkillId, _}, Acc) ->
        SkillR = data_skill:get(SkillId, ?DEFAULT_SKILL_LV),
        SkillR2 = ?IF(is_record(SkillR, skill), SkillR, #skill{}),
        #skill{career = SkillCareer} = SkillR2,
        %% 自动学习, 职业主动非副技能
        case {lists:member(SkillCareer, ?ALL_CAREER_LIST), SkillR2} of
            {true, #skill{type = ?SKILL_TYPE_ACTIVE, is_combo = 0, lv_data = LvData}} ->
                case FilterF =:= skip orelse lists:all(FilterF, LvData#skill_lv.condition) of
                    true -> [SkillR2|Acc];
                    false -> Acc
                end;
            {_, #skill{career = 10, lv_data = #skill_lv{condition = [{lv, 1}] = Condition}}} ->
                %% 一级就可以学习的通用技能，可以自动学习
                case FilterF =:= skip orelse lists:all(FilterF, Condition) of
                    true -> [SkillR2 | Acc];
                    false -> Acc
                end;
            _ ->
                Acc
        end
    end,
    case SkillIds =/= [] of
        true ->
            lists:foldl(F, [], SkillIds);
        false -> []
    end.

filter_vip_expire_skill(SkillList, RoleId, Career, {VipType, VipLv, _TrialLv}) ->
    SkillId = lib_vip_api:get_vip_pre_skill_by_career(Career),
    case lists:keyfind(SkillId, 1, SkillList) of
        {_, 1} ->
            if VipType == ?VIP_NORMAL andalso VipLv > 0 ->
                    SkillList;
                VipType == ?VIP_TRIAL ->
                    SkillList;
                true -> %% 不是VIP,删除特权技能
                    NewSkillList = lists:keydelete(SkillId, 1, SkillList),
                    db:execute(io_lib:format(?sql_del_skill, [RoleId, SkillId])),
                    NewSkillList
            end;
        _ ->
            SkillList
    end.

%%--------------------------------------------------
%% 自动学习技能
%% @param  PS    #player_status{}
%% @param  Event login|{lv,玩家等级}|{turn,玩家转生数,技能替换列表}|{finish_dun,完成副本id}|{transfes, 技能替换列表}
%% @return       description
%%--------------------------------------------------
auto_learn_skill(PS, Event) ->
    #player_status{
        id = RoleId,
        figure = #figure{career = Career, sex = Sex, name = Name, turn = Turn},
        skill= Sk
    } = PS,
    case filter_auto_learn_skill(Career, Sex, Event) of
        CandidateList when CandidateList =/= [] ->
            F = fun(SkillData, {PassiveSkill, SkillListTmp, AddSkillIdsTmp}) ->
                #skill{
                    id=SkillId, type=Type, is_normal = IsNormal, is_combo=0, skill_link = SkillLink, lv_data=LvData
                    ,is_anger = IsAnger
                } = SkillData,
                case lists:keyfind(SkillId, 1, Sk#status_skill.skill_list) of
                    false ->
                        case check_upgrade(PS, LvData#skill_lv.condition, [0, 0, [], SkillId]) of
                            {true, _} -> %% 满足条件没有学
                                NPassiveSkill = ?IF(Type == ?SKILL_TYPE_PASSIVE, [SkillId|PassiveSkill], PassiveSkill),
                                db_update_skill(RoleId, SkillId, 1, 0),
                                case IsNormal =:= 1 of
                                    true when is_list(SkillLink) andalso SkillLink =/= [] ->
                                        {NPassiveSkill, [{SkillId, 1}|SkillListTmp], AddSkillIdsTmp};
                                    true ->
                                        {NPassiveSkill, [{SkillId, 1}|SkillListTmp], [{SkillId, Type, IsAnger} | AddSkillIdsTmp]};
                                    _ when Type == ?SKILL_TYPE_PASSIVE -> %% 被动不用新学习的列表
                                        {NPassiveSkill, [{SkillId, 1}|SkillListTmp], AddSkillIdsTmp};
                                    _ ->
                                        {NPassiveSkill, [{SkillId, 1}|SkillListTmp], [{SkillId, Type, IsAnger} | AddSkillIdsTmp]}
                                end;
                            _ -> %% 不满足条件
                                {PassiveSkill, SkillListTmp, AddSkillIdsTmp}
                        end;
                    _ -> %% 已经学习了这个技能
                        {PassiveSkill, SkillListTmp, AddSkillIdsTmp}
                end
            end,
            SkillList = Sk#status_skill.skill_list,
            {AddPassiveSkills, NewSkillList, AddSkills} = lists:foldl(F, {[], SkillList, []}, CandidateList),
            NewStatusSkill = Sk#status_skill{skill_list = NewSkillList},
            PS2 = PS#player_status{skill = NewStatusSkill},
            PS3 = quickbar_api:after_auto_learn_skill(PS2, Turn, AddSkills, Event),
            %% 自动学习技能后需要处理的逻辑
            NewPS = after_auto_learn_skill(PS3, AddSkills, SkillList, Event),
            if
                Event =/= login andalso (AddSkills =/= [] orelse AddPassiveSkills =/= []) ->
                    send_my_skill_list(NewPS),
                    case AddPassiveSkills =/= [] of
                        true ->
                            case Event of
                                {finish_dun, DunId} ->
                                    [PSkillId|_] = AddPassiveSkills,
                                    DunName = lib_dungeon_api:get_dungeon_name(DunId),
                                    DunLv = lib_dungeon_api:get_dungeon_condition_lv(DunId),
                                    lib_chat:send_TV(all, 210, 1, [Name, RoleId, DunLv, DunName, PSkillId]);
                                _ ->
                                    skip
                            end,
                            {ok, TipsBinData} = pt_130:write(13020, [AddPassiveSkills]),
                            lib_server_send:send_to_sid(PS#player_status.sid, TipsBinData),
                            LastPS = case lists:member(?SP_SKILL_KILLING, AddPassiveSkills) of
                                false ->
                                    update_skill_attribute_for_ps(NewPS);
                                true  ->
                                    NewPS1 = lib_goods_buff:add_goods_temp_buff(NewPS, ?BUFF_TEAM_SHOW, [{?SPBUFF_REBOUND, 1}], 0),
                                    lib_goods_buff:send_buff_notice(NewPS1),
                                    update_skill_attribute_for_ps(NewPS1)
                            end,
                            case Event of
                                %% 升级计算属性前、登录事件的后续会计算属性，所以不调用计算
                                {lv, _} -> {ok, LastPS};
                                login   -> {ok, LastPS};
                                _ ->    % 其他在线情况需要重新计算属性
                                    {ok, lib_player:count_player_attribute(LastPS)}
                            end;
                        false ->
                            %% 主动型技能也可能有战力数据更新，需要重新计算技能的战力相关属性
                            LastPS = update_skill_attribute_for_ps(NewPS),
                            {ok, LastPS}
                    end;
                true ->
                    {ok, NewPS}
            end;
        _ -> {ok, PS}
    end.

%% 自动学习技能后需要处理的逻辑
after_auto_learn_skill(Role, AddSkills, SkillList, Event) ->
    Role2 = after_learn_anger_skill(Role, AddSkills, SkillList, Event),
    VipSkills = data_vip:get_cfg(3),
    lists:map(fun({SkillId, _Type, _IsAnger}) ->
        case lists:member(SkillId, VipSkills) of
            true -> lib_server_send:send_to_sid(Role#player_status.sid, pt_210, 21001, [?SUCCESS, SkillId]);
            _    -> skip
        end
    end, AddSkills),
    Role2.

%% 自动学习怒气技能后，加满怒气。
after_learn_anger_skill(Role, AddSkills, SkillList, Event) ->
    IsFirstAngerSkill = case [Id || {Id, ?SKILL_TYPE_ACTIVE, 1} <- AddSkills] of
        AngerSkillIds = [_|_] -> check_first_learn(AngerSkillIds, SkillList);
        _ -> false
    end,
    #player_status{battle_attr = BattleAttr} = Role,
    Anger = ?ANGER_MAX,
    Role2 = case IsFirstAngerSkill of
        true ->
            Role#player_status{battle_attr = BattleAttr#battle_attr{anger = Anger}};
        false ->
            Role
    end,
    case Event =/= login andalso IsFirstAngerSkill of
        true ->
            mod_scene_agent:update(Role2, [{anger, Anger}]),
            pp_player:handle(13086, Role2, []);
        _ ->
            ok
    end,
    Role2.

check_first_learn([Id | AngerSkillIds], SkillList) ->
    case lists:keyfind(Id, 1, SkillList) of
        false -> true;
        _ -> check_first_learn(AngerSkillIds, SkillList)
    end;
check_first_learn([], _SkillList) ->
    false.


%% ---------------------------------------------------------------------------
%% @doc 升级技能
-spec upgrade_skill(Role, SkillId) -> {false, ErrCode} | {true, NewRole, SkillData} when
    Role        :: #player_status{},
    SkillId     :: integer(),
    ErrCode     :: integer(),
    NewRole     :: #player_status{},
    SkillData   :: #skill{}.
%% ---------------------------------------------------------------------------
upgrade_skill(Role, SkillId) ->
    case check_skill_upgrade(Role, SkillId, normal) of
        {false, Reason}->
            {false, Reason};
        {true, Coin, GoodsList, Data, Lv0, Type} ->
            %% 扣金币和物品
            GoodsList2 = ?IF(Coin > 0, [{?TYPE_BGOLD, 0, Coin} | GoodsList], GoodsList),
            case lib_goods_api:cost_object_list_with_check(Role, GoodsList2, upgrade_skill, "") of
                {false, ErrCode, _Role2} ->
                    {false, ErrCode};
                {true, Role3, _CostList} ->
                    #skill{skill_link = SkillLink, type = SkillType} = Data,
                    Role4 = update_status_skill(Role3, SkillId, Lv0, SkillLink, Type),
                    %% 被动技能属性加成
                    Role5 = case SkillType of
                        ?SKILL_TYPE_PASSIVE -> update_skill_attribute_for_ps(Role4);
                        _ -> Role4
                    end,
                    %% 人物属性计算
                    #player_status{
                        skill=SkillStatus, id = RoleId,
                        figure = #figure{name = Name, lv = RoleLv}
                    }=Role5,
                    #status_skill{skill_list=SkillList}=SkillStatus,
                    {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(SkillList, RoleLv),
                    NSkillStatus=SkillStatus#status_skill{skill_attr = SkillAttr, skill_power = SkillPower},
                    Role6 = Role5#player_status{skill=NSkillStatus},
                    NewRole = lib_player:count_player_attribute(Role6),
                    mod_scene_agent:update(NewRole, [{battle_attr, NewRole#player_status.battle_attr}]),
                    lib_player:send_attribute_change_notify(NewRole, ?NOTIFY_ATTR),
                    lib_log_api:log_skill_active([RoleId, Name, SkillId, Lv0, util:term_to_bitstring(GoodsList2), utime:unixtime()]),
                    case Lv0 =:= 1 of
                        true ->
                            handle_achievement(NewRole, Data, active);
                        _ ->
                            case data_skill:get(SkillId, Lv0) of
                                #skill{type=?SKILL_TYPE_ACTIVE}->
                                    lib_task_api:active_skill_lv(NewRole);
                                _->
                                    skip
                            end,
                            handle_achievement(NewRole, Data, upgrade)
                    end,
                    {true, NewRole, Data}
            end
    end.

%% skill_list中已经包含所有的技能
handle_achievement(Role, SkillData, OptionType) ->
    #player_status{figure = Figure, skill = #status_skill{
        skill_list = AllSkillList},
        vip_status = RoleVip
    } = Role,
    #figure{career = Career} = Figure,
    #skill{id = SkillId, is_normal = Normal, career = SkillCareer, obj = Obj} = SkillData,
    OtherActiveSkill = lists:seq(109001, 109008),
    IsOtherActive = lists:member(SkillId, OtherActiveSkill),
    IsNormal = Normal =:= 1,
    %% 特殊技能包含晨星落，百万剑库，永恒回复，禁跳，流血，虚弱，定身
    SpecSkill = [101091, 102091, 103091, 104091, 109100, 109101, 120001, 120002, 120003],
    IsSpec = lists:member(SkillId, SpecSkill),
    if
        %% 职业技能，需要排除普通技能和大招(职业技能也包含被动技能,因此放在最前面)
        (SkillCareer =:= Career orelse IsOtherActive) andalso not IsNormal andalso not IsSpec ->
            case OptionType of
                active ->
                    handle_active_skill(
                        Role, Career, AllSkillList, OtherActiveSkill, SpecSkill
                    );
                upgrade ->
                    handle_upgrade_skill(
                        Role, Career, AllSkillList, OtherActiveSkill, SpecSkill
                    );
                _ ->
                    ignore
            end;
        %% 被动技能
        SkillCareer =:= ?SKILL_CAREER_COMMON, Obj =:= 7 ->
            handle_passive_skill(Role, AllSkillList);
        true ->
            %% 特殊技能
            case lists:member(SkillId, SpecSkill) of
                true ->
                    #vip_status{sup_vip = SupVip} = RoleVip,
                    VipSkills = case SupVip#role_sup_vip.type > 0 of
                                    true -> [{109101, 1}];
                                    _ -> []
                                end,
                    VisusSkills = lib_role_visus:get_skills(Role),
                    handle_spec_skill(
                        Role, lists:ukeysort(1, AllSkillList ++ VipSkills ++ VisusSkills), SpecSkill
                    );
                _ ->
                    ignore
            end
    end.

handle_active_skill(Role, Career, AllSkillList, OtherActiveSkill, SpecSkill) ->
    %% 激活数量
    CalcF = fun({TSkillId, _}, TNum) ->
        case data_skill:get(TSkillId, 1) of
            #skill{career = TCareer, is_normal = TNormal} ->
                IsOther = lists:member(TSkillId, OtherActiveSkill),
                IsSpec  = lists:member(TSkillId, SpecSkill),
                case (TCareer =:= Career orelse IsOther) andalso TNormal =/= 1 andalso (not IsSpec) of
                    true -> TNum +1;
                    _ -> TNum
                end;
            _ -> TNum
        end end,
    SumNum = lists:foldl(CalcF, 0, AllSkillList),
    lib_achievement_api:career_skill_active_event(Role, SumNum),
    ok.

handle_upgrade_skill(Role, Career, AllSkillList, OtherActiveSkill, SpecSkill) ->
    %% 升级次数
    lib_achievement_api:career_skill_up_event(Role, 1),
    lib_seven_days_goal:finish_task(Role#player_status.id, 210, 1, 1),
    %% 满级数量
    CalcF = fun({TSkillId, TLv} = TSkill, TList) ->
        case data_skill:get(TSkillId, TLv) of
            #skill{career = TCareer, is_normal = TNormal} ->
                IsOther = lists:member(TSkillId, OtherActiveSkill),
                IsSpec  = lists:member(TSkillId, SpecSkill),
                case (TCareer =:= Career orelse IsOther) andalso TNormal =/= 1 andalso (not IsSpec) of
                    true -> [TSkill|TList];
                    _ -> TList
                end;
            _ -> TList
        end end,
    SkillList = lists:foldl(CalcF, [], AllSkillList),
    lib_achievement_api:career_skill_lv_event(Role, SkillList),
    ok.

handle_passive_skill(Role, AllSkillList) ->
    CalcF = fun({TSkillId, TLv}, TSumLv) ->
        case data_skill:get(TSkillId, TLv) of
            #skill{career = TCareer, obj = TObj}
                when TCareer =:= ?SKILL_CAREER_COMMON, TObj =:= 7->
                TLv + TSumLv;
            _ -> TSumLv
        end end,
    SumLv = lists:foldl(CalcF, 0, AllSkillList),
    lib_achievement_api:passive_skill_event(Role, SumLv),
    ok.

handle_spec_skill(Role, AllSkillList, SpecSkill) ->
    CalcF = fun({TSkillId, _TLv}, TSumNum) ->
        IsOtherSkill = lists:member(TSkillId, SpecSkill),
        case IsOtherSkill of
            true -> TSumNum + 1;
            _ -> TSumNum
        end end,
    SumNum = lists:foldl(CalcF, 0, AllSkillList),
    lib_achievement_api:active_spec_skill_event(Role, SumNum),
    ok.

%% --------------------------------------------------------------------------------
%% @doc 自动检查技能是否还有效。例如：vip失效，部分技能会失效
-spec check_del_skill(Role, Event) -> NewRole when
    Role        :: #player_status{},
    Event       :: term(),          %% {vip_time_out}
    NewRole     :: #player_status{}.
%% ---------------------------------------------------------------------------
check_del_skill(Role, Event) ->
    #player_status{
        id = RoleId, skill= StatusSkill, quickbar = Quickbar
    } = Role,
    #status_skill{skill_list = SkillList} = StatusSkill,
    {DelSkills, NewSkillList} = calc_del_skills(Role, SkillList, [], []),
    case DelSkills of
        [] ->
            Role;
        _ ->
            NewStatusSkill = StatusSkill#status_skill{skill_list = NewSkillList},
            DelSkillIds = [SkillId || {SkillId, _Lev} <- DelSkills],
            NewQuickbar = quickbar_api:adjustment_quick_bar(Quickbar, DelSkills),
            %% 快捷栏不需要检查存库，后面会重新检查填补空缺再确定是否写入
            db_del_skill(RoleId, DelSkillIds),
            Role2 = Role#player_status{skill= NewStatusSkill, quickbar = NewQuickbar},
            %% 先刷新技能列表
            case Event =/= login of
                true ->
                    send_my_skill_list(Role2);
                false ->
                    ok
            end,
            NewRole = update_skill_attribute_for_ps(Role2),
            %% 重算战力
            lib_player:count_player_attribute(NewRole)
    end.

%% 获取哪些技能需要删除
%% (要包含怒气技能，主要针对的就是怒气技能)
calc_del_skills(_Role, [], DelSkills, SkillList) ->
    {DelSkills, SkillList};
calc_del_skills(Role, [{SkillId, Lev} | T], DelSkills, SkillList) ->
    VipSkill = lib_vip_api:get_vip_pre_skill_by_career(Role#player_status.figure#figure.career),
    if 
        SkillId == VipSkill ->
            {NewDelSkills, NewSkillList} = case data_skill:get(SkillId, Lev) of
                #skill{lv_data = LvData, type = ?SKILL_TYPE_ACTIVE, is_normal = 0} ->
                    case check_upgrade(Role, LvData#skill_lv.condition, [0, 0, [], SkillId]) of
                        {true, _} ->    %% 仍然满足条件
                            {DelSkills, [{SkillId, Lev} | SkillList]};
                        _ ->            %% 不满足条件
                            {[{SkillId, Lev} | DelSkills], SkillList}
                    end;
                _ ->                    %% 找不到配置或技能类型不符也不删除
                    {DelSkills, [{SkillId, Lev} | SkillList]}
            end,
            calc_del_skills(Role, T, NewDelSkills, NewSkillList);
        true -> %% 不是VIP技能的保留
            calc_del_skills(Role, T, DelSkills, [{SkillId, Lev}|SkillList])
    end.

%% 计算技能列表战力
%% @return SkillList :: [{SkillId, SkillLv}]
count_skill_power(SkillList) ->
    lists:sum([lib_skill_api:get_skill_power(SkillId, SkillLv)||{SkillId, SkillLv}<-SkillList]).

%% 重新计算技能属性
update_skill_attribute_for_ps(PS = #player_status{skill = StatusSkill, figure = Figure}) ->
    #figure{lv = RoleLv} = Figure,
    #status_skill{skill_list = SkillList} = StatusSkill,
    {SkillAttr, SkillPower} = lib_skill_attr:get_passive_skill_attr_and_power(SkillList, RoleLv),
    HpResumeSpclAdd = count_hp_resume_spcl_add(RoleLv, SkillList),
    NewStatusSkill = StatusSkill#status_skill{
        skill_attr = SkillAttr,
        skill_power = SkillPower,
        hp_resume_spcl_add = HpResumeSpclAdd
    },
    PS#player_status{skill = NewStatusSkill}.

%% 更新升级时影响到的特殊属性
update_spcl_attr_with_lv_up(PS) ->
    NewPS = update_skill_attribute_for_ps(PS),
    {ok, NewPS}.

%% 属性列表转化map
%% tranc_skill_attr([{AttrId, AttrVal}|T], AttrMaps, OtherMaps) ->
%%     if
%%         AttrId == ?SPEED_ADD_RATIO orelse AttrId == ?HP_RESUME orelse AttrId == ?EXP_ADD_RATIO orelse
%%         AttrId == ?BOSS_HURT_ADD_RATIO orelse AttrId == ?PVE_SKILL_HURT ->
%%             tranc_skill_attr(T, AttrMaps, OtherMaps#{AttrId => AttrVal+maps:get(AttrId, OtherMaps, 0)});
%%         true ->
%%             tranc_skill_attr(T, AttrMaps#{AttrId => AttrVal+maps:get(AttrId, AttrMaps, 0)}, OtherMaps)
%%     end;
%% tranc_skill_attr([_H|T], AttrMaps, OtherMaps) -> tranc_skill_attr(T, AttrMaps, OtherMaps);
%% tranc_skill_attr([], AttrMaps, OtherMaps) -> {AttrMaps, OtherMaps}.

get_normal_skill(Player) ->
    #player_status{skill = StatusSkill} = Player,
    case StatusSkill of
        #status_skill{skill_list = SkillList} ->
            [
                {Id, Lv} || {Id, Lv} <- SkillList, lib_skill_api:is_normal(Id)
            ];
        _ ->
            []
    end.

%% 获取角色创建角色时候的普攻技能
get_ori_normal_skill(Career, Sex) ->
    AllIds = data_skill:get_ids(Career, Sex),
    NormalIds = lists:filter(fun({Id, _Lv}) -> lib_skill_api:is_normal(Id) end, AllIds),
    case NormalIds of
        [] -> 0;
        NormalIds ->
            {MinId, _} = lists:min(NormalIds),
            MinId
    end.

%% 分离出战斗计算的被动
divide_passive_skill(SkillList)->
    F = fun({SkillId, SkillLv}, PassiveSkill) ->
        case data_skill:get(SkillId, SkillLv) of
            #skill{type=Type, lv_data = LvData} when
                  Type == ?SKILL_TYPE_PASSIVE ->
                case LvData#skill_lv.base_attr of
                    [] -> [{SkillId, SkillLv}|PassiveSkill];
                    _ -> PassiveSkill
                end;
            _ -> PassiveSkill
        end
    end,
    lists:foldl(F, [], SkillList).

%% 分离主动技能
divide_active_skill(SkillList) ->
    F = fun({SkillId, SkillLv}, AccSkills) ->
        case data_skill:get(SkillId, SkillLv) of
            #skill{type=?SKILL_TYPE_ACTIVE} -> [{SkillId, SkillLv}|AccSkills];
            _ -> AccSkills
        end
    end,
    lists:foldl(F, [], SkillList).

%% ================================= 天赋技能  =================================

%% 获取天赋技能类型信息
%% @return {UsePoint:: 已使用天赋点, SkillPower::技能战力, TypeSkillList::天赋类型列表}
get_talent_skill_type_info(SkillTalentList)->
    F = fun({SkillId, SkillLv}, {Point, Power, AccTypeList}) ->
        case data_skill:get(SkillId, SkillLv) of
            #skill{lv_data=#skill_lv{power = SkilllPower}} -> skip;
            _ -> SkilllPower = 0
        end,
        TalentType = data_skill_talent:get_talent_type(SkillId),
        NewTList = case lists:keyfind(TalentType, 1, AccTypeList) of
            false ->
                [{TalentType, SkillLv, [{SkillId, SkillLv}]}|AccTypeList];
            {TalentType, TypePoint, TypeList} ->
                Elem = {TalentType, TypePoint+SkillLv, [{SkillId, SkillLv}|TypeList]},
                lists:keystore(TalentType, 1, AccTypeList, Elem)
        end,
        {Point+SkillLv, Power+SkilllPower, NewTList}
    end,
    lists:foldl(F, {0, 0, []}, SkillTalentList).

%% 获取一类天赋投入的天赋点数
get_talent_type_use_point(TalentType, SkillTalentList)->
    F = fun({SkillId, SkillLv}, UsePoint) ->
        Type = data_skill_talent:get_talent_type(SkillId),
        if
            TalentType == Type -> UsePoint + SkillLv;
            true -> UsePoint
        end
    end,
    lists:foldl(F, 0, SkillTalentList).

%% 天赋技能开启默认技能点
give_def_talent_skill_point(Ps) ->
    #player_status{id = RoleId, figure = #figure{turn = Turn, lv = Lv}, skill = SkillStatus} = Ps,
    if
        Turn < 5 ->  Ps;
        true ->
            LvPoint = max(Lv - 500, 0),
            NewSkillStatus = SkillStatus#status_skill{point = LvPoint + ?DEF_SKILL_POINT},
            db:execute(io_lib:format(?sql_update_talent_skill_point, [?DEF_SKILL_POINT, RoleId])),
            Ps#player_status{skill = NewSkillStatus}
    end.

%% 学习天赋技能
learn_talent_skill(PS, SkillId) ->
    #player_status{sid = Sid, figure = #figure{career = Career, turn = Turn}, skill = SkillStatus} = PS,
    #status_skill{skill_talent_list = SkillTalentList, use_point = UsePoint, point = AllPoint} = SkillStatus,
    SkillLv = case lists:keyfind(SkillId, 1, SkillTalentList) of false -> 1; {_, OSkillLv} -> OSkillLv + 1 end,
    CheckLearn = lib_skill:check_talent_skill_learn(SkillId, SkillLv, UsePoint, AllPoint, SkillTalentList, Career),
    case {Turn < 5, CheckLearn} of
        {true, _} ->
            {ok, Bin} = pt_210:write(21011, [?LEVEL_LIMIT, 0, 0, 0]),
            lib_server_send:send_to_sid(Sid, Bin);
        {false, {fail, ErrCode}} ->
            {ok, Bin} = pt_210:write(21011, [ErrCode, 0, 0, 0]),
            lib_server_send:send_to_sid(Sid, Bin);
        {false, true} -> learn_talent_skill_core(PS, SkillId, SkillLv)
    end.

learn_talent_skill_core(PS, SkillId, SkillLv) ->
    #player_status{id = RoleId, sid = Sid, skill = SkillStatus, figure = #figure{lv = RoleLv}} = PS,
    #status_skill{skill_talent_list = SkillTalentList, point = AllPoint} = SkillStatus,
    db:execute(io_lib:format(?sql_replace_talent_skill, [RoleId, SkillId, SkillLv])),
    NewSkillTalentList = lists:keystore(SkillId, 1, SkillTalentList, {SkillId, SkillLv}),
    %% {TalentAttrMap, TalentOtherMap} = lib_skill_attr:get_passive_skill_attr(NewSkillTalentList, RoleLv),
    TalentAttr = lib_skill_attr:get_passive_skill_attr(NewSkillTalentList, RoleLv),
    NewSkillTalentPassive = lib_skill:divide_passive_skill(NewSkillTalentList),
    NewSkillTalentActive = lib_skill:divide_active_skill(NewSkillTalentList),
    {NewUsePoint, Power, _TypeSkillList} = lib_skill:get_talent_skill_type_info(NewSkillTalentList),
    NewSkillStatus = SkillStatus#status_skill{
        skill_talent_list = NewSkillTalentList,
        skill_talent_passive = NewSkillTalentPassive,
        skill_talent_attr = TalentAttr,
        use_point = NewUsePoint,
        skill_talent_power = Power
    },
    %% 计算天赋技能对其它功能的属性影响
    NewPS = PS#player_status{skill = NewSkillStatus},
    NewPS2 = lib_player:count_func_attribute(SkillId, SkillLv, NewPS),
    LastPS = lib_player:count_player_attribute(NewPS2),
    lib_player:send_attribute_change_notify(LastPS, ?NOTIFY_ATTR),
    {ok, Bin} = pt_210:write(21011, [1, SkillId, SkillLv, max(0, AllPoint-NewUsePoint)]),
    lib_server_send:send_to_sid(Sid, Bin),
    mod_scene_agent:update(LastPS, [
            {passive_skill, NewSkillTalentPassive},
            {skill_talent_active_list, NewSkillTalentActive},
            {battle_attr, LastPS#player_status.battle_attr}
        ]),
    {ok, LastPS}.

%% 学习天赋进程检查
check_talent_skill_learn(SkillId, SkillLv, UsePoint, AllPoint, SkillTalentList, Career)->
    CommonSkillIdList = data_skill_talent:get_skill_ids(0),
    AllSkillList = data_skill_talent:get_skill_ids(Career) ++ CommonSkillIdList,
    IsTalentSkill = lists:member(SkillId, AllSkillList),
    %% 不区分职业的天赋技能 技能职业字段填的是?SKILL_CAREER_COMMON
    IsNotDiffCareer = ?IF(lists:member(SkillId, CommonSkillIdList), true, false),
    TalentCareer = ?IF(IsNotDiffCareer == true, ?SKILL_CAREER_COMMON, Career),
    if
        AllPoint - UsePoint =< 0 -> {fail, ?ERRCODE(err210_point_not_enough)};
        IsTalentSkill =/= true -> {fail, ?ERRCODE(err_not_talent_learn)};
        true ->
            CareerSkillList = data_skill:get_ids(TalentCareer),
            case lists:keyfind(SkillId, 1, CareerSkillList) of
                false -> {fail, ?ERRCODE(err210_not_mycarrer_talent_skill)};
                {_SkillId, SkillMaxLv} ->
                    if
                        SkillLv > SkillMaxLv -> {fail, ?ERRCODE(err210_skill_max_lv)};
                        true ->
                            case data_skill:get(SkillId, SkillLv) of
                                #skill{lv_data=#skill_lv{condition = Condition}} ->
                                    check_talent_skill_learn_cond(Condition, SkillTalentList);
                                _ -> {fail, ?MISSING_CONFIG}
                            end
                    end
            end
    end.

check_talent_skill_learn_cond([], _SkillTalentList) -> true;
check_talent_skill_learn_cond([H|Condition], SkillTalentList) ->
    case H of
        {point, SkillType, NeedPoint} ->
            case get_talent_type_use_point(SkillType, SkillTalentList) >= NeedPoint of
                true -> check_talent_skill_learn_cond(Condition, SkillTalentList);
                _ -> {fail, ?ERRCODE(err210_no_pre_skill_point)}
            end;
        {pre_skill, SkillId, SkillLv} ->
            case lists:keyfind(SkillId, 1, SkillTalentList) of
                false -> {fail, ?ERRCODE(err210_no_pre_skill)};
                {_, OSkillLv} when OSkillLv < SkillLv -> {fail, ?ERRCODE(err210_no_pre_skill_lv)};
                _ -> check_talent_skill_learn_cond(Condition, SkillTalentList)
            end;
        _R ->
            ?ERR("error talent skill learn condition:~p~n", [_R]),
            {fail, ?ERRCODE(err210_skill_erro)}
    end.

%% 重置天赋技能
reset_talent_skill(PS)->
    #player_status{sid = Sid, figure = #figure{turn = Turn}, skill = SkillStatus} = PS,
    #status_skill{skill_talent_list = SkillTalentList, point = AllPoint} = SkillStatus,
    case {Turn < 5, SkillTalentList == []} of
        {true, _} ->
            {ok, Bin} = pt_210:write(21012, [?LEVEL_LIMIT, 0]),
            lib_server_send:send_to_sid(Sid, Bin);
        {false, true} ->
            {ok, BinData} = pt_210:write(21012, [?ERRCODE(err210_no_learn_talent_skill), 0]),
            lib_server_send:send_to_sid(Sid, BinData);
        {_, _} ->
            case lib_goods_api:cost_object_list_with_check(PS, [{0, ?TALENT_RESET_GOOD, 1}], talent_skill_reset, "") of
                {true,NewPS0} ->
                    NewPS = reset_talent_skill_core(NewPS0),
                    LastPS = lib_player:count_player_attribute(NewPS),
                    lib_player:send_attribute_change_notify(LastPS, ?NOTIFY_ATTR),
                    {ok, BinData} = pt_210:write(21012, [1, AllPoint]),
                    lib_server_send:send_to_sid(Sid, BinData),
                    mod_scene_agent:update(LastPS, [
                            {delete_passive_skill, SkillTalentList},
                            {skill_talent_active_list, []},
                            {battle_attr, LastPS#player_status.battle_attr}]),
                    {ok, LastPS};
                {_Res,_,_} ->
                    {ok, BinData} = pt_210:write(21012, [?ERRCODE(goods_not_enough), AllPoint]),
                    lib_server_send:send_to_sid(Sid, BinData)
            end
    end.

%% 重置天赋技能：返回Ps
reset_talent_skill_core(PS)->
    #player_status{id = RoleId, skill = SkillStatus, figure = Figure} = PS,
    if
        Figure#figure.turn < 5 -> PS;
        true ->
            db:execute(io_lib:format(?sql_reset_talent_skill, [RoleId])),
            NewSkillStatus = SkillStatus#status_skill{
                use_point = 0, skill_talent_power = 0, skill_talent_list = [],
                skill_talent_passive = [], skill_talent_active_list = [],
                skill_talent_attr = #{}, skill_talent_attr_other = #{}},
            PS#player_status{skill = NewSkillStatus}
    end.

%% 触发天赋主动技能
trigger_talent_active(PS, OldSkillId, SkillId, LastTime) ->
    #player_status{sid = Sid, skill = SkillStatus} = PS,
    EndTime = utime:longunixtime() + LastTime + 600,
    TalentActiveTriggers = SkillStatus#status_skill.skill_talent_active_triggers,
    NewTalentActiveTriggers = lists:keystore(SkillId, 1, TalentActiveTriggers, {SkillId, EndTime}),
    NewPS = PS#player_status{skill = SkillStatus#status_skill{skill_talent_active_triggers = NewTalentActiveTriggers}},
    {ok, BinData} = pt_210:write(21015, [OldSkillId, SkillId, EndTime]),
    lib_server_send:send_to_sid(Sid, BinData),
    {ok, NewPS}.

%% 获取天赋主动技能信息
get_talent_active_info(SkillStatus, SkillId, NowTime) ->
    #status_skill{skill_talent_list = SkillTalentList, skill_talent_active_triggers = ActiveTriggers} = SkillStatus,
    case lists:keyfind(SkillId, 1, ActiveTriggers) of
        {SkillId, EndTime} when EndTime > NowTime ->
            case lists:keyfind(SkillId, 1, SkillTalentList) of
                {SkillId, SkillLv} -> {SkillId, SkillLv};
                _ -> false
            end;
        _ -> false
    end.

%% ================================= private fun =================================
%% 获取所有技能主被动技能
get_all_skill(Id) ->
    SkillList = db:get_all(io_lib:format(?sql_get_all_skill, [Id])),
    F = fun([SkillId, SkillLv], L) ->
                case data_skill:get(SkillId, SkillLv) of
                    #skill{is_combo=0} -> [{SkillId, SkillLv}|L];
                    _ -> L
                end
        end,
    lists:foldl(F, [], SkillList).

%% 所有的天赋技能
get_all_talent_skill(RoleId)->
    SkillList = db:get_all(io_lib:format(?sql_get_all_talent_skill, [RoleId])),
    [{SkillId, SkillLv} || [SkillId, SkillLv] <- SkillList].

%% 更新技能列表
update_status_skill(Status, SkillId, SkillLv, SkillLink, Type) ->
    Sk = Status#player_status.skill,
    AddSkillList = [SkillId | SkillLink],
    F = fun(TmpSkillId, SkillList) -> [{TmpSkillId, SkillLv}|lists:keydelete(TmpSkillId, 1, SkillList)] end,
    NewSkillList = lists:foldl(F, Sk#status_skill.skill_list, AddSkillList),
    UpdateList = [{TmpSkillId, SkillLv} || TmpSkillId <- AddSkillList],
    [db_update_skill(Status#player_status.id, Id, Lv, Type) || {Id, Lv} <- UpdateList],
    Status#player_status{skill = Sk#status_skill{skill_list=NewSkillList}}.

%% 更新数据库
db_update_skill(Id, SkillId, Lv, Type) ->
    case Type of
        0 -> db:execute(io_lib:format(?sql_insert_skill, [Id, SkillId, Lv]));
        _ -> db:execute(io_lib:format(?sql_update_skill_lv, [Lv, Id, SkillId]))
    end.

%% ---------------------------------------------------------------------------
%% @doc 删除技能
-spec db_del_skill(RoleId, SkillIdList) -> ok when
    RoleId      :: integer(),
    SkillIdList :: [SkillId :: integer()].
%% ---------------------------------------------------------------------------
db_del_skill(RoleId, SkillIdList) ->
    NewSkillIdList = [
        erlang:integer_to_list(SkillId) || SkillId <- SkillIdList
    ],
    SkillIdsStr = string:join(NewSkillIdList, ","),
    db:execute(io_lib:format(?sql_batch_del_skill, [RoleId, SkillIdsStr])),
    ok.

%% ================================= 技能条件检查 =================================
%% 技能升级检查
check_skill_upgrade(Status, SkillId, Flag) ->
    #player_status{figure = Figure, skill = Sk} = Status,
    #figure{career = Career, sex = Sex} = Figure,
    case lists:keyfind(SkillId, 1, lib_skill_api:get_career_all_skill_ids(Career, Sex)) of
        false -> {false, ?MISSING_CONFIG};
        {_, MaxLv} ->
            SkillList = case Flag of
                normal -> Sk#status_skill.skill_list;
                _ -> ?ERR("unkown flag:~p~n", [Flag]), []
            end,
            {Data, Lv0, Type} = case lists:keyfind(SkillId, 1, SkillList) of
                false -> {data_skill:get(SkillId, 1), 1, 0};
                {_, Lv} -> {data_skill:get(SkillId, Lv+1), Lv+1, 1}
            end,
            if
                Lv0 > MaxLv -> {false, ?ERRCODE(err210_skill_max_lv)};
                not is_record(Data, skill) -> {false, ?ERRCODE(err210_skill_error)};
                SkillId == ?SUPVIP_FORBID_JUMP_SKILL ->
                    {false, ?ERRCODE(err210_active_sup_vip)};
                true ->
                    case check_upgrade(Status, Data#skill.lv_data#skill_lv.condition, [0, 0, [], SkillId]) of
                        {true, [Coin, _Point, GoodsList]} -> {true, Coin, GoodsList, Data, Lv0, Type};
                        Res -> Res
                    end
            end
    end.

%% 技能升级条件检查
check_upgrade(Status, [], [Coin, Point, GoodsList|_]) ->
    NewGoodsList = lib_goods_api:make_reward_unique(GoodsList),
    case lib_goods_api:check_object_list(Status, NewGoodsList) of
        true -> {true, [Coin, Point, GoodsList] };
        {false, ErrCode} -> {false, ErrCode}
    end;
check_upgrade(Status, [H | T], [Coin, Point, GoodsList, SkillId]) ->
    case H of
        {lv, V} -> %% 等级需求
            case Status#player_status.figure#figure.lv < V of
                true  -> {false, ?ERRCODE(err210_lv_not_enough)};
                false -> check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId])
            end;
        {vip, V} -> %% vip等级需求
            case lib_vip_api:check_is_vip_previlege_skill(SkillId) of
                false ->
                    case Status#player_status.figure#figure.vip < V of
                        true  -> {false, ?ERRCODE(err210_vip_lev_not_enough)};
                        false -> check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId])
                    end;
                true ->
                    #player_status{vip_status = #vip_status{
                        type = VipType, trial_lv = TrialLv, lv = RealLv}} = Status,
                    RoleVipLv = if VipType == ?VIP_NORMAL -> RealLv;
                        true -> TrialLv
                    end,
                    if RoleVipLv < V ->
                            {false, ?ERRCODE(err210_vip_lev_not_enough)};
                        true ->
                            check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId])
                    end
            end;
        {coin, V} -> %% 铜币需求
            case Status#player_status.coin < V of
                true  -> {false, ?ERRCODE(err210_coin_not_enough)};
                false -> check_upgrade(Status, T, [Coin+V, Point, GoodsList, SkillId])
            end;
        {point, V} -> %% 技能点
            #player_status{skill=Skill} = Status,
            case Skill#status_skill.point < Skill#status_skill.use_point + V of
                true  -> {false, ?ERRCODE(err210_point_not_enough)};
                false -> check_upgrade(Status, T, [Coin, Point+V, GoodsList, SkillId])
            end;
        {turn, V} -> %% 转生
            #player_status{figure=#figure{turn=Turn}} = Status,
            case Turn >= V of
                false ->  {false, ?ERRCODE(turn_not_enough)};
                true ->  check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId])
            end;
        {finish_dun, V} ->
            case lib_dungeon_api:check_ever_finish(Status, V) of
                true ->
                    check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId]);
                false ->
                    {false, ?FAIL}
            end;
        {skill, Id, Lv} ->
            Sk = Status#player_status.skill,
            case lists:keyfind(Id, 1, Sk#status_skill.skill_list) of
                false ->  {false, ?ERRCODE(err210_no_pre_skill)};
                {_, Lv0} when Lv0 < Lv-> {false, ?ERRCODE(err210_no_pre_skill_lv)};
                _ -> check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId])
            end;
        {goods, ObjectType, GoodsId, GoodsNum} ->
            NewGoodsList = [{ObjectType, GoodsId, GoodsNum}|GoodsList],
            check_upgrade(Status, T, [Coin, Point, NewGoodsList, SkillId]);
        {goods, GoodsId, GoodsNum} ->
            NewGoodsList = [{?TYPE_GOODS, GoodsId, GoodsNum}|GoodsList],
            check_upgrade(Status, T, [Coin, Point, NewGoodsList, SkillId]);
        {task, TaskId} ->
            case lib_role_task:is_finish_task_id(TaskId) of
                true ->
                    check_upgrade(Status, T, [Coin, Point, GoodsList, SkillId]);
                false ->
                    {false, ?FAIL}
            end;
        _ ->
            % ?ERR("unkown match:~p~n", [H]),
            {false, ?FAIL}
            % check_upgrade(Status, T, [Coin, Point, GoodsList])
    end.

%% 特殊技能hp回复增量值
count_hp_resume_spcl_add(RoleLv, SkillList) ->
    case lists:keyfind(?SP_SKILL_HP_RESUME, 1, SkillList) of
        {_, SkillLv} ->
            data_hp_resume:get(RoleLv, SkillLv);
        _ ->
            0
    end.

%% -------------------------------------------------------------
%% 调试是否更新血量回复值
%% NOTE: 开发调试专用，游戏中不可调用
debug_check_hp_resume(Id) ->
    Pid = misc:get_player_process(Id),
    PS = sys:get_state(Pid),
    #player_status{skill = StatusSkill, battle_attr = BA, figure = Figure} = PS,
    #status_skill{skill_list = SkillList, hp_resume_spcl_add = HpResumeSpclAdd} = StatusSkill,
    #figure{lv = RoleLv} = Figure,
    #battle_attr{hp_resume_add = HpResumeAdd} = BA,
    SkillLv = case lists:keyfind(?SP_SKILL_HP_RESUME, 1, SkillList) of
        {_, LvX} -> LvX;
        _ -> 0
    end,
    ExpectSpclAdd = count_hp_resume_spcl_add(RoleLv, SkillList),
    #{
        role_lv => RoleLv, skill_lv => SkillLv,
        expect_spcl_add => ExpectSpclAdd,
        hp_resume_spcl_add => HpResumeSpclAdd,
        hp_resume_add => HpResumeAdd
    }.
%% -------------------------------------------------------------

%%计算主动技能的升级次数
calc_lv_times(NeedNum,Status)->
    #player_status{skill = Sk} = Status,
    calc_lv_times(Sk#status_skill.skill_list,0,NeedNum).
calc_lv_times([],Times,_NeedNum)->
    Times;
calc_lv_times([{SkillId,Lv}|T],Times,NeedNum)->
    case data_skill:get(SkillId, Lv) of
        #skill{type=?SKILL_TYPE_ACTIVE}->
            NewTimes = Times+Lv-1,
            case NewTimes>=NeedNum of
                true->
                    NeedNum;
                _->
                    calc_lv_times(T,NewTimes,NeedNum)
            end;
        _->
           calc_lv_times(T,Times,NeedNum)
    end.