%% ---------------------------------------------------------
%% Author:  zmh
%% Created: 2019-11-11
%% Description: 玩家进阶系统
%% --------------------------------------------------------
-module(lib_role_foster).
-compile(export_all).
-include("server.hrl").
-include("role_foster.hrl").
-include("predefine.hrl").
-include("skill.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("rec_event.hrl").
-include("def_event.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("goods.hrl").
-include("common.hrl").
-include("attr.hrl").
-include("fashion.hrl").


-export([
	login/1,          %%登录加载
	get_sub_foster/2, %%获取子系统
	do_foster_up/2,   %%升阶
	save_role_foster/2, %%保存
	check_up_flag/3,    %%判断是否升阶升星
	after_foster_up/3,  %%升阶之后
	eat_core_pill/4,     %%吞噬核心药
	handle_event/2,      %%事件处理
	update_role_foster/3, %%数据保存
	update_role_figure/1,
	change_display/3,
	change_hoese_state/3,
	foster_skill_lvup/4,
	count_foster_attr/1,
	calc_power/3,

	pack_14600/2,
	is_can_resolve/2,
	pack_14600/1,
	db_load/2

    ,get_foster_battle_attr/2           %% 获取某个培养系统的属性
    ,update_foster_attr_to_scene/2      %% 更新培养系统属性到场景
    ,check_have_learn_skill/3           %% 检查玩家是否已学习了指定技能

	,calc_all_foster/2                  %% 统计所有进阶
	,calc_foster_skills/1               %% 统计所有技能
	,get_foster_passive_skill/1			%% 获取被动技能
    ,gm/1

    ,use_stuff_up_fosters/3
    ,calc_equip_assist_active/4
    ,equip_attr_access/3
	]).

%% -------------------------------------------------------------------------------
%% @doc gm相关 @end
gm(Status)->
	#player_status{
		id=RoleID,
		cell_num = CellNum,
        storage_num = StorageNum,
        figure = #figure{lv = Lv},
        scene = Scene,
        scene_pool_id = PoolID,
        copy_id = CopyId,
        x = X, y = Y
    }=Status,
	All = data_foster:get_fosters(),
	Fosters = gm_trans(RoleID,All,[]),
	Status0 = Status#player_status{role_foster=#role_foster{fosters=Fosters}},
	Status1 = count_foster_attr(Status0),
	Status2 = update_role_figure(Status1),
	NStatus = lib_player:count_player_attribute(Status2),
    lib_player:send_attribute_change_notify(NStatus, ?NOTIFY_ATTR),
    BattleAttr = NStatus#player_status.battle_attr,
    %% 物品初始化
    GoodsStatus = lib_goods_do:login(RoleID, Lv, CellNum, StorageNum),
    lib_goods_do:init_data(GoodsStatus),
    pp_goods:handle(15010, NStatus, [?GOODS_LOC_FHORSE_EQUIP_BAG]),
    pp_goods:handle(15010, NStatus, [?GOODS_LOC_FJARVIS_EQUIP_BAG]),

    %%场景广播
    {ok, Bin1} = pt_120:write(12016, [?MOD_FOSTER,14609,RoleID,1]),
    %%场景广播
    {ok, Bin2} = pt_120:write(12016, [?MOD_FOSTER,?FHORSE,RoleID,1]),
    %%场景广播
    {ok, Bin3} = pt_120:write(12016, [?MOD_FOSTER,?FWEAPON,RoleID,1]),
    Bin = <<Bin1/binary,Bin2/binary,Bin3/binary>>,
    lib_server_send:send_to_area_scene(Scene,PoolID,CopyId,X,Y,Bin),

    #player_status{figure=LFigure}=NStatus,
    mod_scene_agent:update(NStatus,[{speed, BattleAttr#battle_attr.speed},{foster_ride,1},{role_foster,LFigure#figure.role_foster}]),

    NStatus.

gm_trans(_,[],Fosters)->
	Fosters;
gm_trans(RoleID,[H|T],Fosters)->
	PosL = data_foster:get(skill_pos_list),
	Skills = gm_trans_skills(PosL,H,[]),
	Grade = calc_max_grade(H,0),
	Star = calc_max_star(H,Grade,0),
	LCore = calc_max_core(H,0),
	HCore = calc_max_core(H,1),
	HCore1 = calc_max_core(H,2),
	HCore2 = calc_max_core(H,3),
	Equips = auto_equip(RoleID,Grade,H),
	Display = 1,
	IsRide  = case H of
		          ?FHORSE->
			          1;
		          _->
			          0
	          end,
	CoreExt = [{2, HCore1}, {3, HCore2}],
	Cell = #cell_foster{
		type = H,
		display = Display,
		state = IsRide,
		grade = Grade,
		star = Star,
		lowcore = LCore,
		highcore = HCore,
		core_ext = CoreExt,
		skills = Skills,
		equips = Equips,
		base_skill = get_base_skill(H)
	},
	save_role_foster(RoleID,Cell),
	gm_trans(RoleID,T,[Cell|Fosters]).


auto_equip(RoleID,Grade,Type)->
	PosL = data_foster:get(equip_pos_list),
	case lists:member(Type,[?FHORSE,?FJARVIS]) of
		true->
			LocEquip = case Type of
		        ?FHORSE->
		            ?GOODS_LOC_FHORSE_EQUIP_BAG;
		        ?FJARVIS->
		            ?GOODS_LOC_FJARVIS_EQUIP_BAG;
		        _->
		            0
		    end,
   			db:execute("delete from goods where location=~p and role_id=~p", [LocEquip,RoleID]),
   			auto_equip(RoleID,Grade,Type,PosL,[]);
   		_->
   			[]
   	end.

 auto_equip(_RoleID,0,_Type,_PosL,Equips)->
 	Equips;
 auto_equip(RoleID,Grade,Type,PosL,Equips)->
 	SubEquips = auto_grade_equip(RoleID,Grade,Type,PosL,[]),
 	NEquips = [#grade_equip{grade=Grade,equips=SubEquips}|Equips],
 	auto_equip(RoleID,Grade-1,Type,PosL,NEquips).

auto_grade_equip(_RoleID,_Grade,_Type,[],Equips)->
	Equips;
auto_grade_equip(RoleID,Grade,Type,[H|T],Equips)->
	GType = gm_calc_gtype(Type,H),
	case data_foster:get_foster_equip(GType) of
         #equip_conf{color=Color}->
         	skip;
         _->
         	Color = 0
    end,
    FEquip = #foster_equip{
    	pos = H,
    	gtype = GType,
    	color = Color,
    	lv = 1
    },
    LocEquip = case Type of
        ?FHORSE->
            ?GOODS_LOC_FHORSE_EQUIP_BAG;
        ?FJARVIS->
            ?GOODS_LOC_FJARVIS_EQUIP_BAG;
        _->
            0
    end,
    case GType>0 of
    	true when LocEquip>0->
    		GoodsTypeInfo = data_goods_type:get(GType),
            GoodsInfo = lib_goods_util:get_new_goods(RoleID, GoodsTypeInfo, []),
            ExtraData = [{?GOODS_OTHER_KEY_FOSTER_LV,1},{?GOODS_OTHER_KEY_FOSTER_EXP,0},{?GOODS_OTHER_KEY_FOSTER_GRADE,Grade}],
    		lib_goods_util:add_goods(
                GoodsInfo#goods{
                    cell = H,
                    num = 1,
                    bind = 1,
                    location = LocEquip,
                    extra_data = ExtraData
                }
            ),
    		auto_grade_equip(RoleID,Grade,Type,T,[FEquip|Equips]);
    	_->
    		auto_grade_equip(RoleID,Grade,Type,T,Equips)
    end.

gm_calc_gtype(?FHORSE,1)->231031;
gm_calc_gtype(?FHORSE,2)->231032;
gm_calc_gtype(?FHORSE,3)->231033;
gm_calc_gtype(?FHORSE,4)->231034;
gm_calc_gtype(?FHORSE,5)->231035;
gm_calc_gtype(?FHORSE,6)->231036;
gm_calc_gtype(?FJARVIS,1)->232031;
gm_calc_gtype(?FJARVIS,2)->232032;
gm_calc_gtype(?FJARVIS,3)->232033;
gm_calc_gtype(?FJARVIS,4)->232034;
gm_calc_gtype(?FJARVIS,5)->232035;
gm_calc_gtype(?FJARVIS,6)->232036;
gm_calc_gtype(_,_)->0.


calc_max_core(Type,C)->
 	#base_foster_core{
 		max = MaxL
 	}=data_foster:get_foster_core(Type,C),
 	{_,Data} =  lists:last(MaxL),
 	Data.

gm_trans_skills([],_,Skills)->
	Skills;
gm_trans_skills([H|T],Type,Skills)->
	MaxL = calc_max_skill_lv(Type,H,0),
	#base_foster_skill{
		skillid = S
	} = data_foster:get_foster_skill(Type,H,MaxL),
	gm_trans_skills(T,Type,[{H,MaxL,S}|Skills]).

calc_max_skill_lv(Type,Pos,Init)->
	case data_foster:get_foster_skill(Type,Pos,Init+1) of
		#base_foster_skill{}->
			calc_max_skill_lv(Type,Pos,Init+1);
		_->
			Init
	end.

calc_max_grade(Type,Init)->
	case data_foster:get_base_foster(Type,Init+1,0) of
		#base_foster{}->
			calc_max_grade(Type,Init+1);
		_->
			Init
	end.

calc_max_star(Type,Grade,Init)->
	case data_foster:get_base_foster(Type,Grade,Init+1) of
		#base_foster{}->
			calc_max_star(Type,Grade,Init+1);
		_->
			Init
	end.

%% -------------------------------------------------------------------------------
%% 玩家上线
login(Status)->
	#player_status{figure=Figure,id=RoleID}=Status,
	#figure{lv=Lv} = Figure,
	Sql = io_lib:format(?SQL_PLAYER_FOSTER_GET, [RoleID]),
	Fosters1 = case db:get_all(Sql) of
        Fosters0 when is_list(Fosters0)  ->
            make_fosters(RoleID,Fosters0,[]);
        _ ->
        	[]
    end,
	%% 没有激活进阶的系统也需要加载皮肤
	LoadSkinsFosters = load_all_skin(RoleID, Fosters1),
    Now = utime:unixtime(),
    Fosters2 = fix_role_foster(RoleID,LoadSkinsFosters,Now,[]),
	%% 卸下槽位上不符合配置要求的装备(异步执行)
	fix_foster:login_fix_equips(RoleID, Fosters2),
    All = filter_open(Lv),
    Fosters3 = case length(All) > length(Fosters2) of
    	true->
    		revise_foster(RoleID,Fosters2,All,[]);
    	_->
    		Fosters2
    end,
    Status0 = update_role_figure(false,Status#player_status{role_foster=#role_foster{fosters=Fosters3}}),
    NStatus = count_foster_attr(Status0),
    %io:format("--:~p~n",[{Shows,Figure#figure.career,Figure#figure.lv_model,NFigure#figure.lv_model}]),
    NStatus.

load_all_skin(RoleID, CellFosters) ->
	F = fun(Type, TCellFosters) ->
		case lists:keyfind(Type, #cell_foster.type, TCellFosters) of
			#cell_foster{} = CellFoster -> ok;
			_ -> CellFoster = #cell_foster{type = Type}
		end,
		FosterSkins = load_sub_foster_skin(RoleID, Type),
		case FosterSkins =/= [] of
			true ->
				case get_display_skin(FosterSkins) of
					{SkinId, DisplayStar} -> ok;
					_ -> SkinId = 0, DisplayStar = 0
				end,
				NewCellFoster = CellFoster#cell_foster{
					skin_list = FosterSkins
					,display_skin = {SkinId, DisplayStar}
				},
				lists:keystore(Type, #cell_foster.type, TCellFosters, NewCellFoster);
			_ ->
				TCellFosters
		end
	end,
	NewCellFosters = lists:foldl(F, CellFosters, ?ALL_FOSTER),
	NewCellFosters.

%% 离线加载(role_show里面数据)
db_load(RoleID,Figure)->
	Sql = io_lib:format(?SQL_PLAYER_FOSTER_GET, [RoleID]),
	Fosters = case db:get_all(Sql) of
        Fosters0 when is_list(Fosters0)  ->
            make_fosters(RoleID,Fosters0,[]);
        _ ->
        	[]
    end,
    Shows = [{Type,Dis}||#cell_foster{type=Type,display=Dis}<-Fosters],
    NFigure0 = Figure#figure{role_foster=Shows},
    NFigure = update_lv_model(NFigure0),
    NFigure.

%%db_load_sub_skin(RoleId, Figure) ->
%%	F = fun(Type, TCellFosters) ->
%%		FosterSkins = load_sub_foster_skin(RoleId, Type),
%%		case FosterSkins =/= [] of
%%			true ->
%%				case get_display_skin(FosterSkins) of
%%					{SkinId, DisplayStar} -> ok;
%%					_ -> SkinId = 0, DisplayStar = 0
%%				end,
%%				NewCellFoster = #cell_foster{
%%					type = Type
%%					,skin_list = FosterSkins
%%					,display_skin = {SkinId, DisplayStar}
%%				},
%%				lists:keystore(Type, #cell_foster.type, TCellFosters, NewCellFoster);
%%			_ ->
%%				TCellFosters
%%		end end,
%%	lists:foldl(F, [], ),
%%	NFigure0 = Figure#figure{foster_sub_skin = Shows},
%%	NFigure = update_lv_model(NFigure0),
%%	NFigure.

%% 登陆校正  配置新增/已达等级系统，自动激活进阶系统
revise_foster(_,_Fosters,[],CellFosters)->
	CellFosters;
revise_foster(RoleID,Fosters,[Type|All],CellFosters)->
	case lists:keyfind(Type,#cell_foster.type,Fosters) of
		#cell_foster{}=CellFoster->%%已开放
			revise_foster(RoleID,Fosters,All,[CellFoster|CellFosters]);
		_->
			CellFoster = case lists:member(Type, ?GRADE_FOSTER) of
							 true -> #cell_foster{type = Type, grade = 1, display = 1};
							 _ -> #cell_foster{type = Type, lv = 1, display = 1}
			             end,
			update_role_foster(main,RoleID,CellFoster),
			NCellFosters0 = lists:keystore(Type,#cell_foster.type,CellFosters,CellFoster),
			NCellFosters  = init_role_foster(RoleID,NCellFosters0,[]),
			revise_foster(RoleID,Fosters,All,NCellFosters)
	end.


%%数据拼接
make_fosters(_,[],CellFosters)->
	CellFosters;
make_fosters(RoleID,[[Type,Grade,Star,Lv,Exp,Click,Clear,Display,_IsRide,LowCore,HighCore,CoreExt,Etime,OSkills]|Fosters],CellFosters)->
	Skills = util:to_term(OSkills),
	Equips = load_role_grade_equip(RoleID,Type),
	{NewGrade, NewStar, NewLv, NewClick, NewClear, NewEndTime, NewDisplay} =
		fix_foster:login_fix_grade(RoleID, Type, Grade, Star, Lv, Click, Clear, Etime, Display),
	NFoster = #cell_foster{
		type = Type,
		grade= NewGrade,
		star = NewStar,
		lv   = NewLv,
		exp  = Exp,
		click = NewClick,
		clear= NewClear,
		display  = NewDisplay,
		lowcore  = LowCore,
		highcore = HighCore,
		core_ext = util:bitstring_to_term(CoreExt),
		etime= NewEndTime,
		skills= Skills,
		base_skill = get_base_skill(Type),
		equips= Equips
	},
	make_fosters(RoleID,Fosters,[NFoster|CellFosters]).

%% 加载进阶装备
load_role_grade_equip(RoleID,Type)->
    Sql = io_lib:format(?SQL_PLAYER_FOSTER_EQUIP_GET, [RoleID,Type]),
    GradeEquips0 = db:get_all(Sql),
    GradeEquips  = trans_grade_equip(Type,GradeEquips0),
    GradeEquips.

trans_grade_equip(Type,GradeEquips)->
    trans_grade_equip(Type,GradeEquips,[]).
trans_grade_equip(_,[],GradeEquips)->
    GradeEquips;
trans_grade_equip(Type, [[Grade,Equips0,_Assist]|T],GradeEquips)->
    Equips1 = util:bitstring_to_term(Equips0),
    Equips  = trans_equip(Equips1,[]),
    NewAssist = calc_equip_assist_active(Type, Grade, _Assist, Equips),
    trans_grade_equip(Type,T,[#grade_equip{grade=Grade,equips=Equips,assist=NewAssist}|GradeEquips]).

trans_equip([],Equips)->
    Equips;
trans_equip([{Pos,Uid,Gtype,Color,Lv,Exp}|T],Equips)->
    trans_equip(T,[#foster_equip{pos=Pos,uid=Uid,gtype=Gtype,color=Color,lv=Lv,exp=Exp}|Equips]).

%% 加载进阶皮肤
load_sub_foster_skin(RoleId, Type) ->
	Sql = io_lib:format(?SQL_PLAYER_SUB_FOSTER_SKIN_SELECT, [RoleId, Type]),
	FosterSkinInfos = db:get_all(Sql),
	FosterSkins  = trans_sub_foster_skin(FosterSkinInfos, []),
	FosterSkins.

trans_sub_foster_skin([], FosterSkins) -> FosterSkins;
trans_sub_foster_skin([SkinInfo|T], FosterSkins) ->
	case SkinInfo of
		[SkinId, Star, DisplayStar] ->
			CellSkin =
			#sub_cell_foster_skin{
				skin_id = SkinId, star = Star,
				display_star = DisplayStar
			},
			NewFosterSkins = lists:keystore(SkinId, #sub_cell_foster_skin.skin_id,
				FosterSkins, CellSkin
			),
			trans_sub_foster_skin(T, NewFosterSkins);
		_ ->
			trans_sub_foster_skin(T, FosterSkins)
	end.

get_display_skin(FosterSkins) ->
	F = fun(SkinInfo, DisplayInfo) ->
		case SkinInfo of
			#sub_cell_foster_skin{skin_id = SkinId, display_star = DisStar} when DisStar > 0 ->
				{SkinId, DisStar};
			_ ->
				DisplayInfo
		end end,
	lists:foldl(F, {0, 0}, FosterSkins).

%% 获取类型对应的名字
get_type_name(Type) ->
	case Type of
		1 ->
			"座驾";
		2 ->
			"炫翼";
		3 ->
			"宝具";
		4 ->
			"武器";
		5 ->
			"Ai娘";
		6 ->
			"磁炮";
		7 ->
			"星翼";
		8 ->
			"幻甲";
		_ ->
			""
	end.

%%获取子系统信息
get_sub_foster(Type,Status)->
	#player_status{role_foster=RoleFoster}=Status,
	#role_foster{fosters=CellFosters}=RoleFoster,
	case lists:keyfind(Type,#cell_foster.type,CellFosters) of
		CellFoster when is_record(CellFoster,cell_foster) ->
			{1,CellFoster};
		_->
			{0,#cell_foster{type=Type}}
	end.

%%数据校正 Exp清零
fix_role_foster(_RoleID,[],_Now,CellFosters)->
	CellFosters;
fix_role_foster(RoleID,[Foster|Fosters],Now,CellFosters)->
	#cell_foster{
		clear = Clear,
		etime = Etime
	} = Foster,
	case Clear == 1 of
		true->
			case Etime>Now of
				true->
					fix_role_foster(RoleID,Fosters,Now,[Foster|CellFosters]);
				_->
					NFoster = Foster#cell_foster{exp=0,click=0,etime=Now+?CLEAR_TIME},
					save_role_foster(RoleID,NFoster),
					fix_role_foster(RoleID,Fosters,Now,[NFoster|CellFosters])
			end;
		_->
			fix_role_foster(RoleID,Fosters,Now,[Foster|CellFosters])
	end.

%% -------------------------- 数据更新 --------------------------------------
%% 主体数据
update_role_foster(main,RoleID,Foster)->
    #cell_foster{
		type = Type,
		grade= Grade,
		star = Star,
	    lv   = Lv,
		exp  = Exp,
		click = Click,
		display = Dis,
		%state = IsRide,
		clear= IsClear,
		lowcore  = LowCore,
		highcore = HighCore,
	    core_ext = CoreExt,
		etime= ETime,
		skills= OSkills
	} = Foster,
	Skills = util:term_to_string(OSkills),
	CoreExtStr = util:term_to_string(CoreExt),
	Sql = io_lib:format(?SQL_PLAYER_FOSTER_INSERT,[RoleID,Type,Grade,Star,Lv,Exp,Click,IsClear,Dis,0,LowCore,HighCore,CoreExtStr,ETime,Skills]),
    db:execute(Sql);
%% 技能
update_role_foster(skill,RoleID,Foster)->
	#cell_foster{
		type = Type,
		skills = Skills0
	} = Foster,
	Skills = util:term_to_string(Skills0),
	Sql = io_lib:format(?SQL_UPDATE_FOSTER_SKILL,[Skills,RoleID,Type]),
    db:execute(Sql);
%% 核心
update_role_foster(core,RoleID,Foster)->
    #cell_foster{
        type = Type,
       	lowcore = LowCore,
       	highcore = HighCore,
	    core_ext = CoreExt
    } = Foster,
	CoreExtStr = util:term_to_string(CoreExt),
    Sql = io_lib:format(?SQL_UPDATE_FOSTER_CORE, [LowCore,HighCore,CoreExtStr,RoleID,Type]),
    db:execute(Sql);
%% 幻化类型
update_role_foster(display,RoleID,Foster)->
    #cell_foster{
        type = Type,
       	display = Dis
    } = Foster,
    Sql = io_lib:format(?SQL_UPDATE_FOSTER_DISPLAY, [Dis,RoleID,Type]),
    db:execute(Sql);
%% 骑乘状态
update_role_foster(horse_state,RoleID,Foster)->
    #cell_foster{
        type = Type,
       	state = IsRide
    } = Foster,
    Sql = io_lib:format(?SQL_UPDATE_FOSTER_HORSE, [IsRide,RoleID,Type]),
    db:execute(Sql);
%% 装备
update_role_foster({equips,Grade},RoleID,Foster)->
	#cell_foster{
		type = Type,
		equips = GradeEquips
	} = Foster,
	case lists:keyfind(Grade,#grade_equip.grade,GradeEquips) of
		#grade_equip{equips=Equips0,assist=Assist}->
			Equips1 = [{Pos,Uid,Gtype,Color,Lv,Exp}||#foster_equip{pos=Pos,uid=Uid,gtype=Gtype,color=Color,lv=Lv,exp=Exp}<-Equips0],
    		Equips  =  util:term_to_string(Equips1),
			Sql = io_lib:format(?SQL_PLAYER_FOSTER_EQUIP_INT,[RoleID,Type,Grade,Equips,Assist]),
    		db:execute(Sql);
    	_A->
    		ignore
    end;
update_role_foster(sub_foster_skin, RoleId, DbInfo) ->
	[Type, SkinId, Star, DisplayStar] = DbInfo,
	Sql = io_lib:format(?SQL_PLAYER_SUB_FOSTER_SKIN_INSERT, [RoleId, Type, SkinId, Star, DisplayStar]),
	db:execute(Sql);
update_role_foster(_,_,_)->ignore.


%%持久化数据
save_role_fosters(_RoleID,[])->
	ignore;
save_role_fosters(RoleID,[Foster|Fosters])->
	save_role_foster(RoleID,Foster),
	save_role_fosters(RoleID,Fosters).

save_role_foster(RoleID,Foster)->
	#cell_foster{
		type = Type,
		equips= GradeEquips
	} = Foster,
	update_role_foster(main,RoleID,Foster),
   	save_grade_equips(RoleID,Type,GradeEquips).

%%数据保存
save_grade_equip(RoleID,Type,GradeEquip)->
    #grade_equip{grade=Grade,equips=Equips0,assist=Assist}=GradeEquip,
    Equips1 = [{Pos,Uid,Gtype,Color,Lv,Exp}||#foster_equip{pos=Pos,uid=Uid,gtype=Gtype,color=Color,lv=Lv,exp=Exp}<-Equips0],
    Equips  =  util:term_to_string(Equips1),
    SQL = io_lib:format(?SQL_PLAYER_FOSTER_EQUIP_INT, [RoleID,Type,Grade,Equips,Assist]),
    db:execute(SQL).

save_grade_equips(_RoleID,_Type,[])->
    skip;
save_grade_equips(RoleID,Type,GradeEquips)->
    Values = [ begin
        Equips1 = [{Pos,Uid,Gtype,Color,Lv,Exp}||#foster_equip{pos=Pos,uid=Uid,gtype=Gtype,color=Color,lv=Lv,exp=Exp}<-Equips0],
        Equips  =  util:term_to_string(Equips1),
        io_lib:format("(~p,~p,~p,'~ts',~p)", [RoleID,Type,Grade,Equips,Assist])
    end  || #grade_equip{grade=Grade,equips=Equips0,assist=Assist}<- GradeEquips],
    ValuesStr = ulists:list_to_string(Values, ","),
    SQL = io_lib:format(?SQL_PLAYER_FOSTER_EQUIP_BATCH, [ValuesStr]),
    Values /= [] andalso db:execute(SQL).


auto_foster_up(0,_Status,_AUp,_ABuy,_AutoBGold,_,_,_)->
	{false,?ERRCODE(err146_foster_not_open)};
auto_foster_up(IsOpen,Status,AUp,ABuy,AutoBGold,Foster,Costs,FosterTimes)->
	#cell_foster{
		grade= Grade,
		star = Star
	} = Foster,
	case do_foster_up(IsOpen,Foster) of
		{false,_Err}->
			{ok,Costs,Foster,FosterTimes};
		{ok,Costs0,_,_,NFoster}->
			Costs1 = util:combine_list(Costs0++Costs,1),
			case ABuy>0 of
				true->
					case goods_del:check_object_list(Status, Costs1, role_foster) of
			        	{false, Err} ->
			        		case Err =:= ?GOODS_NOT_ENOUGH of
                				true ->
                					case lib_goods_api:calc_auto_buy_list(Status, Costs1) of
				                        {ok, NewObjectList} ->
				                        	case lists:keyfind(?TYPE_GOLD,1,NewObjectList) of
				                        		{_,_,NeedGold} when NeedGold>0,AutoBGold>=1->%%需要用到彩钻 许可
						                            case goods_del:check_object_list(Status, NewObjectList, role_foster) of
						                                {false, _Err} ->
					        								{ok,Costs,Foster,FosterTimes};
						                                true ->
						                                	#cell_foster{
																grade= NGrade,
																star = NStar
															} = NFoster,
															case NGrade /= Grade orelse NStar /= Star of
																true->
																	{ok,Costs1,NFoster,FosterTimes+1};
																_->
																	auto_foster_up(IsOpen,Status,AUp,ABuy,AutoBGold,NFoster,Costs1,FosterTimes+1)
															end
						                            end;
						                        {_,_,_}-> %%需要用到彩钻 未许可
						                        	{false,?ERRCODE(bgold_not_enough)};
						                        _->
						                        	case goods_del:check_object_list(Status, NewObjectList, role_foster) of
						                                {false, _Err} ->
					        								{ok,Costs,Foster,FosterTimes};
						                                true ->
						                                	#cell_foster{
																grade= NGrade,
																star = NStar
															} = NFoster,
															case NGrade /= Grade orelse NStar /= Star of
																true->
																	{ok,Costs1,NFoster,FosterTimes+1};
																_->
																	auto_foster_up(IsOpen,Status,AUp,ABuy,AutoBGold,NFoster,Costs1,FosterTimes+1)
															end
						                            end
							                end;
				                        _A ->
				                            {ok,Costs,Foster,FosterTimes}
				                    end;
				                _->
				                	{ok,Costs,Foster,FosterTimes}
				            end;
				        _->
				        	#cell_foster{
								grade= NGrade,
								star = NStar
							} = NFoster,
							case NGrade /= Grade orelse NStar /= Star of
								true->
									{ok,Costs1,NFoster,FosterTimes+1};
								_->
									auto_foster_up(IsOpen,Status,AUp,ABuy,AutoBGold,NFoster,Costs1,FosterTimes+1)
							end
				    end;
				_->
					case goods_del:check_object_list(Status, Costs1, role_foster) of
			        	{false, _Err} ->
			        		{ok,Costs,Foster,FosterTimes};
			        	true ->
			        		#cell_foster{
								grade= NGrade,
								star = NStar
							} = NFoster,
							case NGrade /= Grade orelse NStar /= Star of
								true->
									{ok,Costs1,NFoster,FosterTimes+1};
								_->
									auto_foster_up(IsOpen,Status,AUp,ABuy,AutoBGold,NFoster,Costs1,FosterTimes+1)
							end
					end
			end
	end.


%%进阶
do_foster_up(0,_)->
	{false,?ERRCODE(err146_foster_not_open)};
do_foster_up(_IsOpen,Foster)->
	#cell_foster{
		type = Type,
		grade= Grade,
		star = Star,
		exp  = Exp,
		click = Click,
		display = Dis,
		etime = OETime
	} = Foster,
	CheckList = [
        {check_max,Type,Grade,Star}
    ],
    case util:check_lists(?MODULE,CheckList) of
        {ok,{Config,NGrade,NStar}}->
        	#base_foster{min=Min,max=Max,rate=Rate,cost=Costs} = Config,
			Now = utime:unixtime(),
			case Exp >= Min of
				true->%%满足保底
					case urand:rand(1,1000)=<Rate of
						true->%%发生暴击  直接升级
							#base_foster{clear=IsClear}=data_foster:get_base_foster(Type,NGrade,NStar),
							NFoster = Foster#cell_foster{
								grade  = NGrade,
								star   = NStar,
								exp    = 0,
								click  = 0,
								clear  = IsClear,
								display = NGrade,
								etime  = Now
							},
							{ok,Costs,1,Max-Exp,NFoster};
						_->%%暴击触发失败
							AddExp = get_per_add(Max-Exp),
							{IsChange,NewGrade,NewStar,NewExp,NClick} = do_add_exp(Type,Grade,Star,Exp,Max,AddExp,Click),
							#base_foster{clear=IsClear}=data_foster:get_base_foster(Type,NewGrade,NewStar),
							NDis = case Grade /= NewGrade of
								true->
									NewGrade;
								_->
									Dis
							end,
							NFoster = Foster#cell_foster{
								grade  = NewGrade,
								star   = NewStar,
								exp    = NewExp,
								click  = NClick,
								clear  = IsClear,
								display= NDis,
								etime  = calc_etime(IsChange,OETime,Exp,Now)
							},
							{ok,Costs,0,AddExp,NFoster}
					end;
				_-> %%正常搞事
					AddExp = get_per_add(Max-Exp),
					{IsChange,NewGrade,NewStar,NewExp,NClick} = do_add_exp(Type,Grade,Star,Exp,Max,AddExp,Click),
					#base_foster{clear=IsClear}=data_foster:get_base_foster(Type,NewGrade,NewStar),
					NDis = case Grade /= NewGrade of
						true->
							NewGrade;
						_->
							Dis
					end,
					NFoster = Foster#cell_foster{
						grade  = NewGrade,
						star   = NewStar,
						exp    = NewExp,
						click  = NClick,
						clear  = IsClear,
						display= NDis,
						etime  = calc_etime(IsChange,OETime,Exp,Now)
					},
					{ok,Costs,0,AddExp,NFoster}
		    end;
		{false,Err}->
			{false,Err}
	end.

%% 统计所有进阶
calc_all_foster(GradeType, Fosters) ->
	Value = util:ceil(GradeType/4),   %% 前4类进阶,类型为9;后4类进阶,类型为10
	Type  = case Value == 1 of
		       true -> 9;
		       _ -> 10
	       end,
	F = fun(#cell_foster{type = FosterType, grade = Grade, skin_list = SkinList}, CalcList) ->
			Value0 = util:ceil(FosterType/4),
			case Value0 == Value of                     %% Value相等，则同为强进阶(进阶)/弱进阶(伙伴)
				true  ->
					Value1 = FosterType rem 4,          %% 强进阶/弱进阶都分4子类
					SubType = case Value1 of
						          0 -> 4;
						          _ -> Value1
					          end,
					case lists:member(FosterType, ?GRADE_FOSTER) of
						true ->
							case lists:keyfind({SubType, Grade}, 1, CalcList) of
								{_, Num} -> lists:keystore({SubType, Grade}, 1, CalcList, {{SubType, Grade}, Num + 1});
								_ -> lists:keystore({SubType, Grade}, 1, CalcList, {{SubType, Grade}, 1})
							end;
						_ ->
							F = fun(SubSkin, TList) ->
								case SubSkin of
									#sub_cell_foster_skin{star = Star} ->
										case lists:keyfind({SubType, Star}, 1, TList) of
											{_, Num} -> lists:keystore({SubType, Star}, 1, TList, {{SubType, Star}, Num + 1});
											_ -> lists:keystore({SubType, Star}, 1, TList, {{SubType, Star}, 1})
										end;
									_ ->
										TList
								end end,
							SubSkinColorList = lists:foldl(F, [], SkinList),
							SubSkinColorList ++ CalcList
					end;
				_ -> CalcList
			end end,
	ColorList = lists:foldl(F, [], Fosters),
	{Type, ColorList}.

%%判断是否升阶升星
check_up_flag(OGrade,OStar,Foster)->
	 #cell_foster{
	 	grade=Grade,
	 	star=Star
	 } = Foster,
	 case OGrade /= Grade of
	 	true->
	 		true;
	 	_->
	 		Star /= OStar
	 end.


%%计算有效时间
calc_etime(IsChange,OETime,OExp,Now)->
	case IsChange>0 of
		true when OETime=<Now-> %%上个计时已完成 重新计时
			Now;
		true->
			case OExp=<0 of
				true->
					Now+?CLEAR_TIME;
				_->
					OETime
			end;
		_->
			case OExp=<0 of
				true->
					Now+?CLEAR_TIME;
				_->
					OETime
			end
	end.

%%加经验值
do_add_exp(Type,Grade,Star,Exp,Max,AddExp,Click)->
	Config = data_foster:get_base_foster(Type,Grade,Star),
	#base_foster{next_grade=NGrade,next_star=NStar} = Config,
	case Exp+AddExp>=Max of
		true->
			case NGrade=<0 andalso NStar=<0 of
				true->
					{0,Grade,Star,0,Click+1};
				_ when NStar=<0->
					{1,NGrade,0,0,0};
				_->
					{1,Grade,NStar,0,0}
			end;
		_->
			{0,Grade,Star,Exp+AddExp,Click+1}
	end.

get_per_add(Value)->
	[Add|_] = urand:list_rand_by_weight(data_foster:get(exp_weight),1),
	min(Value,Add).

%% 培养之后升阶激活技能
after_foster_up(true,RoleID,Foster)->
	#cell_foster{
		type=Type,
		clear=IsClear,
		grade=Grade,
		lv   = Lv,
		skills=OSkills,
		etime=Etime
	}=Foster,
	TrueGrade = case lists:member(Type, ?GRADE_FOSTER) of
					true -> Grade;
					_ -> Lv
	            end,
	SkillPosL = data_foster:get(skill_pos_list),
	NSkills = lists:foldl(fun(Pos,Args)->
		NeedG = data_foster:get_open(Type,Pos),
		case NeedG =< TrueGrade of
			true->
				case lists:keyfind(Pos,1,OSkills) of
					false->%%激活
						#base_foster_skill{skillid=Skid}=data_foster:get_foster_skill(Type,Pos,1),
						{ok, Bin} = pt_146:write(14605,[Type,Pos,1,Skid]),
						lib_server_send:send_to_uid(RoleID,Bin),
						lists:keystore(Pos,1,Args,{Pos,1,Skid});
					_->
						Args
				end;
			_->
				Args
		end
	end,OSkills,SkillPosL),
	case IsClear > 0 of
		true->
			Remain = max(Etime-utime:unixtime(),1),
			erlang:send_after(Remain*1000,self(),{mod,?MODULE,clear_exp,[Type]});
		_->
			ignore
	end,
	Foster#cell_foster{skills=NSkills};
after_foster_up(_,_RoleID,Foster)->
	Foster.

%%服用核心药
eat_core_pill(OpTy,Num,IsOpen,Foster)->
	#cell_foster{
		type = Type,
		grade = Grade,
		lv    = Lv,
		lowcore = LowCore,
		highcore = HighCore,
		core_ext = CoreExt
	} = Foster,
	#base_foster_core{
		con=NeedG,
		max=MaxLists,
		cost=Cost
	}=data_foster:get_foster_core(Type,OpTy),
	Value  = case OpTy of
		0 ->
			LowCore;
		1 ->
			HighCore;
		_ ->
			case lists:keyfind(OpTy, 1, CoreExt) of
				{_, TValue} -> TValue;
				_ -> 0
			end
	end,
	TrueGrade = case lists:member(Type, ?GRADE_FOSTER) of
					true -> Grade;
					_ -> Lv
	            end,
	CkList = [
        {check_grade,NeedG,TrueGrade},
        {check_num,TrueGrade,MaxLists,Value+Num},
        {check_open,IsOpen}
    ],
    NCost = [{T,G,V*Num}||{T,G,V}<-Cost],
    case util:check_lists(?MODULE,CkList) of
    	true when OpTy=<0->
    		NFoster = Foster#cell_foster{lowcore=LowCore+Num},
    		{ok,NCost,NFoster};
    	true when OpTy == 1 ->
    		NFoster = Foster#cell_foster{highcore=HighCore+Num},
    		{ok,NCost,NFoster};
	    true when OpTy == 2 orelse OpTy == 3 ->
		    NewValue = Value + Num,
		    NewCoreExt = lists:keystore(OpTy, 1, CoreExt, {OpTy, NewValue}),
		    NFoster = Foster#cell_foster{core_ext = NewCoreExt},
		    {ok, NCost, NFoster};
    	{false,Err}->
    		{false,Err}
    end.

%%幻化变更
change_display(IsOpen,Dis,Foster)->
	CkList = [
		{check_open,IsOpen},
        {check_change_display, Dis,Foster}
    ],
    case util:check_lists(?MODULE,CkList) of
    	true->
    		NFoster = Foster#cell_foster{display=Dis},
    		{ok, NFoster};
    	{false,Err}->
    		{false,Err}
    end.

change_hoese_state(IsOpen,OpTy,Foster)->
	CkList = [
		{check_open,IsOpen},
        {check_change_horse,OpTy,Foster}
    ],
    case util:check_lists(?MODULE,CkList) of
    	true->
    		NFoster = Foster#cell_foster{state=OpTy},
    		{ok, NFoster};
    	{false,Err}->
    		{false,Err}
    end.

%%技能升级
foster_skill_lvup(IsOpen,Type,Pos,Foster)->
	CkList = [
		{check_open, IsOpen},
		{check_skill_open,Type,Pos,Foster},
		{check_skill_max,Type,Pos,Foster}
	],
	case util:check_lists(?MODULE,CkList) of
    	{ok,{NFoster,SkillID,Lv,Cost}}->
    		{ok, NFoster,SkillID,Lv,Cost};
    	{false,Err}->
    		{false,Err}
    end.

%%升级
do_foster_equip_lv(Status,Type,FosterEquip,UpPos,UPGoodsInfo,GoodsInfos)->
    GoodsInfos0 = lists:keysort(#goods.level,GoodsInfos),
    GoodsInfos1 = lists:reverse(GoodsInfos0),
    [NewUPGoodsInfo,Costs] = calc_equip_lv(UPGoodsInfo,Type,UpPos,GoodsInfos1,[]),
    case lib_goods_api:delete_more_by_list(Status, Costs, role_foster_equip) of
        1 ->
            case goods_logic:update_goods_info_extra([NewUPGoodsInfo]) of
            	{ok, [NewGoodsInfo|_]}->
            		NewFosterEquip = trans_foster_equip(NewGoodsInfo,UpPos,FosterEquip),
            		{ok,NewFosterEquip};
            	_R->
            		{false,?FAIL}
            end;
        _R ->
            {false,?FAIL}
    end.

trans_foster_equip(GoodsInfo,UpPos,FosterEquip)->
    case GoodsInfo of
        #goods{id=Uid,goods_id=GType}->
        	[Lv,Exp,Color] = analyse_extra_data(GoodsInfo),
            FosterEquip#foster_equip{
                pos = UpPos,
                uid = Uid,
                gtype = GType,
                color = Color,
                lv = Lv,
                exp = Exp
            };
        _->
            FosterEquip
    end.

%%-----------
%% 检测分解
is_can_resolve(?FHORSE,GoodsInfo) when is_record(GoodsInfo, goods) ->
    #goods{location = Location} = GoodsInfo,
    Location =:= ?GOODS_LOC_FHORSE_BAG;
is_can_resolve(?FJARVIS,GoodsInfo) when is_record(GoodsInfo, goods) ->
    #goods{location = Location} = GoodsInfo,
    Location =:= ?GOODS_LOC_FJARVIS_BAG;
is_can_resolve(_,_) -> false.

calc_equip_lv(UPGoodsInfo,_,_,[],Costs)->
    [UPGoodsInfo,Costs];
calc_equip_lv(UPGoodsInfo,Type,UpPos,[H|T],Costs)->
    [UpLv,CurExp,UpColor] = analyse_extra_data(UPGoodsInfo),
    Add = case H of
        #goods{goods_id = Gid}->
        	[Lv,Base0,Color] = analyse_extra_data(H),
            case data_foster:get_foster_equip(Gid) of
                #equip_conf{exp=Base,pos=Pos}->
                    case data_foster:get_equip_lv(Type,Pos,Color,Lv) of
                        #equip_lv_conf{total=Total}->
                            Base+Total+Base0;
                        _->
                            0
                    end;
                _->
                    0
            end;
        _->
            0
    end,
    case data_foster:get_equip_lv(Type,UpPos,UpColor,UpLv) of
        #equip_lv_conf{next=Next} when Next>0 ->
            {NewLv,NewExp} = calc_up_lv(Type,Add,CurExp,UpLv,UpColor,UpPos),

            NewUPGoodsInfo = update_extra_data(UPGoodsInfo,NewLv,NewExp),

            case is_record(H,goods) of
                true->
                    calc_equip_lv(NewUPGoodsInfo,Type,UpPos,T,[{H#goods.id,H#goods.goods_id,1}|Costs]);
                _->
                    calc_equip_lv(NewUPGoodsInfo,Type,UpPos,T,Costs)
            end;
        _->
            calc_equip_lv(UPGoodsInfo,Type,UpPos,T,Costs)
    end.

calc_up_lv(Type,Add,CurExp,Lv,Color,Pos)->
    case data_foster:get_equip_lv(Type,Pos,Color,Lv) of
        #equip_lv_conf{need=Need,next=Next} when Next>0->
            case CurExp+Add>=Need of
                true->
                    NewExp = max(CurExp+Add-Need,0),
                    calc_up_lv(Type,NewExp,0,Lv+1,Color,Pos);
                _->
                    {Lv,CurExp+Add}
            end;
        _->
            {Lv,CurExp+Add}
    end.

check({is_foster_goods_efftect_cfg, GoodsId}) ->
    case data_goods_effect:get(GoodsId) of
        #goods_effect{effect_list = [_|_]} ->
            true;
        _ ->
            {false, ?ERRCODE(err154_missing_config)}
    end;
check({foster_goods_num, GoodsNum, UseGoodsNum}) ->
    if GoodsNum >= UseGoodsNum andalso UseGoodsNum == 1 ->
            true;
        true ->
            {false, ?ERRCODE(err222_goods_not_enough)}
    end;
check({check_goods_foster_bag,?FHORSE,UPGoodsInfo})->
    #goods{location = Location} = UPGoodsInfo,
    case Location =:= ?GOODS_LOC_FHORSE_BAG of
        true->
            true;
        _->
            {false,?ERRCODE(err146_gooods_no_exist)}
    end;
check({check_goods_foster_bag,?FJARVIS,UPGoodsInfo})->
    #goods{location = Location} = UPGoodsInfo,
    case Location =:= ?GOODS_LOC_FJARVIS_BAG of
        true->
            true;
        _->
            {false,?ERRCODE(err146_gooods_no_exist)}
    end;
check({check_goods_lv_up,Type,FosterEquip})->
    #foster_equip{
    	pos = Pos,
    	lv = Lv,
    	color = Color
    }=FosterEquip,
    case data_foster:get_equip_lv(Type,Pos,Color,Lv) of
        #equip_lv_conf{next=Next} when Next>0->
            true;
        _->
            {false,?ERRCODE(err146_equip_lv_max_reached)}
    end;
check({check_goods_foster_equip,?FHORSE,UPGoodsInfo})->
    #goods{location = Location} = UPGoodsInfo,
    case Location =:= ?GOODS_LOC_FHORSE_EQUIP_BAG of
        true->
            true;
        _->
            {false,?ERRCODE(err146_gooods_no_exist)}
    end;
check({check_goods_foster_equip,?FJARVIS,UPGoodsInfo})->
    #goods{location = Location} = UPGoodsInfo,
    case Location =:= ?GOODS_LOC_FJARVIS_EQUIP_BAG of
        true->
            true;
        _->
            {false,?ERRCODE(err146_gooods_no_exist)}
    end;
check({check_goods_exist,GoodsInfo})->
    case is_record(GoodsInfo,goods) of
        true->
            true;
        _->
            {false,?ERRCODE(err146_gooods_no_exist)}
    end;
check({check_resolve,IsCanResolve})->
    case IsCanResolve of
        true->
            {false,?ERRCODE(err146_some_cant_resolve)};
        _->
            true
    end;
check({check_unlock, CellFoster, Type}) ->
	%% 因为弱进阶系统有可能已经激活皮肤，所以有数据，这里要判断阶数和等级
    case CellFoster of
        #cell_foster{grade = Grade, lv = Lv} ->
	        case lists:member(Type, ?GRADE_FOSTER) of
				true -> TrueGrade = Grade;
				_ -> TrueGrade = Lv
	        end,
	        case TrueGrade > 0 of
				true -> true;
				_ ->  {false,?ERRCODE(err146_foster_not_open)}
	        end;
        _ ->
            {false,?ERRCODE(err146_foster_not_open)}
    end;
check({check_skill_max,Type,Pos,Foster})->
	#cell_foster{
		grade=Grade,
		lv = FosterLv,
		skills=Skills
	} = Foster,
	TrueGrade = case lists:member(Type, ?GRADE_FOSTER) of
		            true -> Grade;
					_ -> FosterLv
	            end,
	case lists:keyfind(Pos,1,Skills) of
		{_,Lv,_}->
			case data_foster:get_foster_skill(Type,Pos,Lv) of
				#base_foster_skill{next_lv=NLv} when NLv=<0->
					{false,?ERRCODE(err146_lv_max_reached)};
				#base_foster_skill{limit=Limit} when TrueGrade<Limit->
					{false,?ERRCODE(err146_need_more_grade)};
				#base_foster_skill{next_lv=Nlv,skillid=SkillID,cost=Cost}->
					NSkills = lists:keystore(Pos,1,Skills,{Pos,Nlv,SkillID}),
					NFoster = Foster#cell_foster{skills=NSkills},
					{ok,{NFoster,SkillID,Nlv,Cost}};
				%% 兼容删配置情况
				_ ->
					{false,?ERRCODE(err146_lv_max_reached)}
			end;
		_->
			{false,?ERRCODE(err146_need_more_grade)}
	end;
check({check_skill_open,Type,Pos,Foster})->
	#cell_foster{grade=Grade, lv = FosterLv} = Foster,
	NeedG = data_foster:get_open(Type,Pos),
	TrueGrade = case lists:member(Type, ?GRADE_FOSTER) of
		            true -> Grade;
		            _ -> FosterLv
	            end,
	case NeedG=<TrueGrade of
		true->
			true;
		_->
			{false,?ERRCODE(err146_need_more_grade)}
	end;
check({check_change_display,Dis,Foster})->
	case Foster of
		#cell_foster{display=Dis}->
			{false,?ERRCODE(err146_display_repeat)};
		#cell_foster{grade=G} when Dis>G orelse G=<0 ->
			{false,?ERRCODE(err146_need_more_grade)};
		#cell_foster{}->
			true;
		_->
			{false,err146_foster_not_open}
	end;
check({check_change_horse,_OpTy,Foster})->
	case Foster of
		#cell_foster{}->
			true;
		_->
			{false,err146_foster_not_open}
	end;
check({check_open,IsOpen})->
	case IsOpen >= 1 of
		true->
			true;
		_->
			%%系统未开放
			{false,?ERRCODE(err146_foster_not_open)}
	end;
check({check_num,Grade,MaxLists,Value})->
	F = fun(CfgInfo, TMax) ->
		case CfgInfo of
			{CfgGrade, Max} when Grade >= CfgGrade -> Max;
			_ -> TMax
		end end,
	Max = lists:foldl(F, 0, MaxLists),
	case Max >= Value of
		true->
			true;
		_->
			%%达到使用上限
			{false,?ERRCODE(err146_limit_usage_reached)}
	end;
check({check_parma, Type, OpTy, Num}) ->
	CheckType   = lists:member(Type, ?ALL_FOSTER),
	CheckOpType = lists:member(OpTy, [0, 1, 2, 3]),
	CheckNum    = Num > 0,
	if
		not CheckType -> {false, ?FAIL};
		not CheckOpType -> {false, ?FAIL};
		not CheckNum -> {false, ?FAIL};
		true -> true
	end;
check({check_grade,NeedG,Grade})->
	case NeedG=<Grade of
		true->
			true;
		_->
			%%需要更高阶位
			{false,?ERRCODE(err146_need_more_grade)}
	end;
check({check_equip_grade, Type, NowGrade,Grade})->
	case data_foster:get_all_suit(Type) of
		[_|_] = SuitList ->
			case lists:member(Grade, SuitList) of
				true ->
					case NowGrade >= Grade of
						true->
							true;
						_ ->
							%% 需要更高阶位
							{false,?ERRCODE(err146_need_more_grade)}
					end;
				_ ->
					{false,?ERRCODE(err146_need_more_grade)}  %% TODO: 该阶位不能放置装备
			end;
		_ ->
			{false,?ERRCODE(err146_need_more_grade)}
	end;
check({check_grade_equip,GoodsInfo,GEquip})->
	#grade_equip{equips=Equips}=GEquip,
	#goods{cell=Cell} = GoodsInfo,
	case lists:keymember(Cell,#foster_equip.pos,Equips) of
		true->
			true;
		_->
			{false,?ERRCODE(err146_gooods_no_exist)}
	end;
check({check_max,Type,Grade,Star})->
	Config = data_foster:get_base_foster(Type,Grade,Star),
	#base_foster{next_grade=NGrade,next_star=NStar} = Config,
	case NGrade=<0 andalso NStar=<0 of
		true->%%双满
			{false,?ERRCODE(err146_foster_max_grade)};%%已满阶
		_ when NStar=<0-> %%升阶
			{ok,{Config,NGrade,0}};
		_ -> %%升星
			{ok,{Config,Grade,NStar}}
	end.

%% 升级触发进阶系统自动开启(有初始等级和属性)
handle_event(Status,#event_callback{type_id = ?EVENT_LV_UP})->
	#player_status{figure=Figure}=Status,
	#figure{lv=Lv}=Figure,
    All      = filter_open(Lv),
    NStatus  = role_lv_up(All,Status),
    {ok, NStatus};
%%任务完成
handle_event(Status, #event_callback{type_id = ?EVENT_FINISH_TASK, data = TaskId}) ->
	#player_status{figure=Figure}=Status,
	#figure{lv=Lv}=Figure,
	Mods = data_module:get_task_mods(TaskId),
	NStatus  =  case lists:member(?MOD_FOSTER,Mods) of
		true->
		    All = filter_open(Lv),
		    role_lv_up(All,Status);
		 _->
		 	Status
	end,
    {ok, NStatus};
handle_event(Status,#event_callback{type_id=?EVENT_LOGIN_CAST})->
	NStatus = click_check(Status),
	{ok,NStatus};
handle_event(Status, _) ->
    {ok, Status}.

%%检测祝福值清理
click_check(Status)->
	#player_status{role_foster=RoleFoster} = Status,
	#role_foster{fosters=CellFosters}=RoleFoster,
	Now = utime:unixtime(),
	%%筛选所有待清理系统
    LimitTime0 = [ETime-Now||#cell_foster{clear=IsClear,etime=ETime}<-CellFosters,IsClear>0,ETime>Now],
    LimitTime1 = lists:sort(LimitTime0),
    case LimitTime1 of
        []->%%没有 不处理
            ignore;
        [CTime|_]->
            case CTime > 0 of
                true->
                    erlang:send_after(CTime*1000,self(),{mod,?MODULE,role_click,[]});
                _->
                   ignore
            end
    end,
    Status.

role_click(Status)->
	#player_status{id=RoleID,role_foster=ORoleFoster} = Status,
	Now = utime:unixtime(),
	#role_foster{fosters=OFosters}=ORoleFoster,
	Fosters = fix_role_foster(RoleID,OFosters,Now,[]),
	[begin
		Bin = pack_14600(Info),
    	lib_server_send:send_to_uid(RoleID, Bin)
    end || Info<-Fosters],
    RoleFoster = ORoleFoster#role_foster{fosters=Fosters},
	NStatus0 = Status#player_status{role_foster=RoleFoster},
	click_check(NStatus0),
	NStatus = lib_player:count_player_attribute(NStatus0),
    lib_player:send_attribute_change_notify(NStatus, 1),
    mod_scene_agent:update(NStatus, [{battle_attr, NStatus#player_status.battle_attr}]),
	NStatus.

role_lv_up([],Status)->
	Status;
role_lv_up([Type|All],Status)->
	#player_status{
        id = RoleID,
        scene = Scene,
        scene_pool_id = PoolID,
        copy_id = CopyId,
        x = X, y = Y,
        role_foster=RoleFoster
    } = Status,
    #role_foster{fosters=Fosters}=RoleFoster,
	case lists:keyfind(Type,#cell_foster.type,Fosters) of
		#cell_foster{}->%%已开放 不处理
			role_lv_up(All,Status);
		_->
			Foster = case lists:member(Type, ?GRADE_FOSTER) of
						true -> #cell_foster{grade = 1, type = Type, display = 1};
						 _ ->  #cell_foster{lv = 1, type = Type, display = 1}
			         end,
			update_role_foster(main,RoleID,Foster),

			NFosters0 = lists:keystore(Type,#cell_foster.type,Fosters,Foster),
			%% 初始化技能
			NFosters  = init_role_foster(RoleID,NFosters0,[]),

			Status0 = Status#player_status{role_foster=RoleFoster#role_foster{fosters=NFosters}},
			Status1 = update_role_figure(Status0),

			Status2 = count_foster_attr(Status1),
			Status3 = lib_player:count_player_attribute(Status2),
            lib_player:send_attribute_change_notify(Status3, ?NOTIFY_ATTR),
            update_foster_attr_to_scene(Status3, Type),

            Bin = pack_14600(Type,Status3),
			lib_server_send:send_to_uid(RoleID, Bin),

            %%场景广播
            {ok, Bin0} = pt_120:write(12016, [?MOD_FOSTER,Type,RoleID,1]),
            lib_server_send:send_to_area_scene(Scene,PoolID,CopyId,X, Y, Bin0),

            LFigure = Status3#player_status.figure,
            mod_scene_agent:update(Status3,[{role_foster,LFigure#figure.role_foster},{battle_attr, Status3#player_status.battle_attr}]),

            role_lv_up(All,Status3)
    end.

%%数据初始化 初始化第一个技能
init_role_foster(_,[],CellFosters)->
	CellFosters;
init_role_foster(RoleID,[Foster|OFosters],NCellFosters)->
	case Foster of
		#cell_foster{type=Type,skills=S} when S /= [] ->
			init_role_foster(RoleID,OFosters,[Foster#cell_foster{base_skill=get_base_skill(Type)}|NCellFosters]);
		#cell_foster{type=Type,skills=[]}->
			case data_foster:get_foster_skill(Type,1,1) of
				#base_foster_skill{skillid=Sid,limit=L} when L==1 ->
					NFoster = Foster#cell_foster{skills=[{1,1,Sid}],base_skill=get_base_skill(Type)},
					update_role_foster(skill,RoleID,NFoster),
					init_role_foster(RoleID,OFosters,[NFoster|NCellFosters]);
				_->
					init_role_foster(RoleID,OFosters,[Foster#cell_foster{base_skill=get_base_skill(Type)}|NCellFosters])
			end
	end.

pack_14600(Type,Status)->
    {_IsOpen,Foster} = lib_role_foster:get_sub_foster(Type,Status),
    pack_14600(Foster).
pack_14600(Foster)->
    #cell_foster{
        type  = Type,
        grade = Grade,
        star  = Star,
	    lv    = Lv,
        exp   = Exp,
        click = Click,
        clear = Clear,
        display  = Display,
        lowcore  = LowCore,
        highcore = HighCore,
	    core_ext = CoreExt,
        etime  = Etime,
        skills = Skills0,
        base_skill = BaseSkill,
        equips = GradeEquips,
        combat = Combat,
        attrs  = Attrs
    } = Foster,
    Skills = case BaseSkill>0 of
    	true->
    		[{0,1,BaseSkill}|Skills0];
    	_->
    		Skills0
    end,
    ReTime = case Clear>0 andalso Exp>0 of
    	true->
    		max(Etime-utime:unixtime(),0);
    	_->
    		0
    end,
	PackCore1 = lists:keystore(0, 1, CoreExt, {0, LowCore}),
	PackCore2 = lists:keystore(1, 1, PackCore1, {1, HighCore}),
	PackCore3 = case lists:keyfind(2, 1, PackCore2) of
		            {_, _} -> PackCore2;
					_ -> lists:keystore(2, 1, PackCore2, {2, 0})
	            end,
	PackCore4 = case lists:keyfind(3, 1, PackCore3) of
		            {_, _} -> PackCore3;
		            _ -> lists:keystore(3, 1, PackCore3, {3, 0})
	            end,
    Equips = pack_grade_equips(Type,GradeEquips,[]),
    {ok,Bin} = pt_146:write(14600, [Type,Grade,Star,Lv,Exp,Click,Clear,Display,PackCore4,ReTime,Combat,Skills,Equips,Attrs]),
    Bin.

pack_grade_equips(_,[],GradeEquips)->
    GradeEquips;
pack_grade_equips(Type,[#grade_equip{grade=Grade,equips=Equips0}|T],GradeEquips)->
    Equips = pack_equips(Type,Grade,Equips0),
	%% todo: 不符合配置的老数据不发送
    pack_grade_equips(Type,T,[{Grade,Equips}|GradeEquips]).

pack_equips(Type,Grade,Equips)->
    Alls = lib_role_foster:get_all_equip_list(Type),
    pack_equips(Alls,Grade,Equips,[]).
pack_equips(_All,_Grade,[],Equips)->
    Equips;
pack_equips(All,Grade,[H|T],Results)->
    #foster_equip{pos=Pos,gtype=GType,color=Color,lv=Lv,exp=Exp}=H,
    case do_get_pos_goods(Grade,Pos,All) of
        #goods{id=Uid}->
            skip;
        _->
            Uid = 0
    end,
    NResults = [{Pos,Uid,GType,Color,Lv,Exp}|Results],
    pack_equips(All,Grade,T,NResults).

%%祝福值清理
clear_exp(Status,Type)->
	#player_status{id=RoleID,role_foster=ORoleFoster} = Status,
	Now = utime:unixtime(),
	#role_foster{fosters=OFosters}=ORoleFoster,
	Fosters = fix_role_foster(RoleID,OFosters,Now,[]),
	NStatus = Status#player_status{role_foster=ORoleFoster#role_foster{fosters=Fosters}},
	{_IsOpen,Foster}  = get_sub_foster(Type,NStatus),
	Bin = pack_14600(Foster),
    lib_server_send:send_to_uid(RoleID, Bin),
    NStatus.

%% ------------------------------------------------------------------------------------
%% @doc 属性计算相关 @end
%% 所有进阶(强、弱进阶)属性汇总
%% return：NewStatus
count_foster_attr(Status)->
	#player_status{role_foster=RoleFoster}=Status,
	#role_foster{fosters=CellFosters}=RoleFoster,
	[Attrs,NCellFosters] = count_cell_fosters_attr(CellFosters),
	NRoleFoster = RoleFoster#role_foster{attr=Attrs,fosters=NCellFosters},
	Status#player_status{role_foster=NRoleFoster}.

count_cell_fosters_attr(CellFosters)->
	count_cell_fosters_attr(CellFosters,[],[]).

count_cell_fosters_attr([],CellFosters,Attrs)->
	[util:combine_list(Attrs),CellFosters];
count_cell_fosters_attr([H|T],CellFosters,Attrs)->
	[CellAttrs,NewH] = count_cell_attr(H),
	count_cell_fosters_attr(T,[NewH|CellFosters],CellAttrs++Attrs).

%% 单个进阶类型属性汇总
count_cell_attr(CellFoster)->
	#cell_foster{
		type = Type,
		grade = Grade,
		star = Star,
		lv   = Lv,
		click = Click,
		lowcore = LowCore,
		highcore = HighCore,
		core_ext = CoreExt,
		skills = Skills0,
		base_skill = BSkill,
		equips = GEquips
		,skin_list = SkinList
	} = CellFoster,
	Skills = case BSkill>0 of
		true->
			[{0,1,BSkill}|Skills0];
		_->
			Skills0
	end,
	%% 区分属性计算
	case lists:member(Type, ?GRADE_FOSTER) of
		true ->
			case data_foster:get_base_foster(Type,Grade,Star) of
				#base_foster{attrs=Attrs0,tem_attrs=TAttrs0} ->
					LvAttrs = [];
				_->
					Attrs0 = [], TAttrs0 = [], LvAttrs = []
			end;
		_ ->
			case data_foster:get_foster_lv(Type, Lv) of
				#base_foster_sub{attr_list = LvAttrs} ->
					Attrs0 = [], TAttrs0 = [];
				_ ->
					Attrs0 = [], TAttrs0 = [], LvAttrs = []
			end
	end,
	#base_foster_core{ext=LExt}=data_foster:get_foster_core(Type,0),
	#base_foster_core{ext=HExt}=data_foster:get_foster_core(Type,1),
	case data_foster:get_foster_core(Type, 2) of
		#base_foster_core{ext = HExt1} -> ok;
		_ -> HExt1 = []
	end,
	case data_foster:get_foster_core(Type, 3) of
		#base_foster_core{ext = HExt2} -> ok;
		_ -> HExt2 = []
	end,
	case lists:keyfind(2, 1, CoreExt) of
		{_, HighCore1} -> ok;
		_ -> HighCore1 = 0
	end,
	case lists:keyfind(3, 1, CoreExt) of
		{_, HighCore2} -> ok;
		_ -> HighCore2 = 0
	end,
	LAttrs = [{A,B*LowCore}||{A,B}<-LExt],
	HAttrs = [{A,B*HighCore}||{A,B}<-HExt],
	HAttrs1 = [{A,B*HighCore1}||{A,B}<-HExt1],
	HAttrs2 = [{A,B*HighCore2}||{A,B}<-HExt2],
	TAttrs = [{A,B*Click}||{A,B}<-TAttrs0],
	SubSkinsAttr = calc_sub_skin_attr(Type, SkinList),
	Attrs1 = util:combine_list(Attrs0++LvAttrs++LAttrs++HAttrs++HAttrs1++HAttrs2++TAttrs++SubSkinsAttr),
	Attrs2 = lib_player_attr:partial_attr_convert(Attrs1),
	Attrs  = Attrs2,
	SkillAttr = calc_skill_attr(Skills,[]),
	EquipAttr0 = calc_equip_attr(Type,GEquips,[]),
	SuitAttr  = calc_suit_attr(Type,GEquips,[]),

	EquipAttr = lib_player_attr:partial_attr_convert(EquipAttr0++SuitAttr),
	TotalAttr = util:combine_list(Attrs++SkillAttr++EquipAttr),
	NCellFoster = CellFoster#cell_foster{attrs=Attrs,skill_attr=SkillAttr,equip_attr=EquipAttr},
	[TotalAttr,NCellFoster].

%% 技能属性
calc_skill_attr([],Attrs)->
	util:combine_list(Attrs);
calc_skill_attr([{_,Lv,SkillID}|Skills],Attrs)->
	case data_skill:get(SkillID,Lv) of
		#skill{lv_data=#skill_lv{base_attr=BAttr0}}->
			BAttr = [{T,V}||{K,T,V}<-BAttr0,K==0],
			calc_skill_attr(Skills,BAttr++Attrs);
		_->
			calc_skill_attr(Skills,Attrs)
	end.

%% 套装属性
%% p.s.: 只有助战状态可激活装备套装属性
calc_suit_attr(_Type,[],Attrs)->
	util:combine_list(Attrs);
calc_suit_attr(Type,[#grade_equip{grade=Grade,equips=Equips,assist=2}|GEquips],Attrs)->
	PosN = length(data_foster:get(equip_pos_list)),
	SAttrs = case length(Equips)>=PosN of
		true->
			case lists:keysort(#foster_equip.color,Equips) of
				[#foster_equip{color=MinColor}|_]->
					skip;
				_->
					MinColor = 0
			end,
			data_foster:get_suit_attr(Type,Grade,MinColor);
		_->
			[]
	end,
	calc_suit_attr(Type,GEquips,Attrs++SAttrs);
calc_suit_attr(Type,[#grade_equip{}|GEquips],Attrs) ->
    calc_suit_attr(Type, GEquips, Attrs).

%% 装备等级属性
%% 只有助战状态可激活装备等级属性
calc_equip_attr(_Type,[],Attrs)->
	util:combine_list(Attrs);
calc_equip_attr(Type,[#grade_equip{equips=Equips,assist=2}|GEquips],Attrs)->
	EAttrs = calc_grade_equip_attr(Type,Equips,[]),
	calc_equip_attr(Type,GEquips,Attrs++EAttrs);
calc_equip_attr(Type,[#grade_equip{}|GEquips],Attrs) ->
    calc_equip_attr(Type,GEquips,Attrs).

calc_grade_equip_attr(_Type,[],Attrs)->
	Attrs;
calc_grade_equip_attr(Type,[#foster_equip{pos=Pos,color=Color,lv=Lv}|Equips],Attrs)->
	case data_foster:get_equip_lv(Type,Pos,Color,Lv) of
		#equip_lv_conf{attrs=GAtttr}->
			calc_grade_equip_attr(Type,Equips,GAtttr++Attrs);
		_->
			calc_grade_equip_attr(Type,Equips,Attrs)
	end.

%% 弱进阶皮肤属性
calc_sub_skin_attr(Type, SkinList) ->
	F = fun(SkinInfo, TAttrList) ->
		case SkinInfo of
			#sub_cell_foster_skin{skin_id = SkinId, star = Star} ->
				case data_foster:get_foster_sub_skin(Type, SkinId, Star) of
					#base_foster_sub_skin{attr_list = Attr} when Star =/= 0 ->
						Attr ++ TAttrList;
					_ ->
						TAttrList
				end;
			_ ->
				TAttrList
		end end,
	AttrList = lists:foldl(F, [], SkinList),
	AttrList.

%% -----------------------------------------------------------------------------------------
%%解析extra
analyse_extra_data(GoodsInfo)->
	#goods{goods_id=GType,extra_data=Extras}=GoodsInfo,
	case data_foster:get_foster_equip(GType) of
         #equip_conf{color=Color}->
         	case lists:keyfind(?GOODS_OTHER_KEY_FOSTER_LV,1,Extras) of
         		{_,Lv}->
         			skip;
         		_->
         			Lv=0
         	end,
         	case lists:keyfind(?GOODS_OTHER_KEY_FOSTER_EXP,1,Extras) of
         		{_,Exp}->
         			skip;
         		_->
         			Exp=0
         	end,
         	[Lv,Exp,Color];
         _->
         	[0,0,0]
    end.
%%更新extra
update_extra_data(GoodsInfo,Lv,Exp)->
	#goods{extra_data=Extras}=GoodsInfo,
	Extras0 = lists:keystore(?GOODS_OTHER_KEY_FOSTER_LV,1,Extras,{?GOODS_OTHER_KEY_FOSTER_LV,Lv}),
	NExtras = lists:keystore(?GOODS_OTHER_KEY_FOSTER_EXP,1,Extras0,{?GOODS_OTHER_KEY_FOSTER_EXP,Exp}),
    GoodsInfo#goods{extra_data=NExtras}.

calc_power(Status, AttrPower, BaseAttr) ->
	#player_status{role_foster=RoleFoster}=Status,
	#role_foster{fosters=Fosters}=RoleFoster,
	[NStatus,NFosters, NeedUpdate,SkillPower|_] = calc_foster_power(Status,AttrPower, BaseAttr, Fosters, [], [],0),
	NRoleFoster = RoleFoster#role_foster{fosters=NFosters},
	NStatus1 = NStatus#player_status{role_foster=NRoleFoster},
	case NeedUpdate of
		[_|_] -> lib_common_rank_api:refresh_rank_by_foster(NStatus1, NeedUpdate);
		_     -> skip
	end,
	{NStatus1, SkillPower}.

calc_foster_power(Status, _AttrPower, _BaseAttr, [], Fosters, NeedUpdate,SkillPower)->
	[Status,Fosters, NeedUpdate,SkillPower];
calc_foster_power(Status, AttrPower, BaseAttr, [CellFoster|T], Fosters, NeedUpdate,SkillPower)->
	#cell_foster{
		type = CellType,
		attrs = CellAttrs,
		equip_attr = EquipAttr,
		combat = OldCombat,
		base_skill = BSkill,
		skills = Skills0
	}=CellFoster,
	Skills = case BSkill>0 of
		true->
			[{0,1,BSkill}|Skills0];
		_->
			Skills0
	end,
	NSkills = [{K,V}||{_,V,K}<-Skills],
    RoleLv = Status#player_status.figure#figure.lv,
	{_,SPower}  = lib_skill_attr:get_passive_skill_attr_and_power(NSkills, RoleLv),
	SkillAttr   = calc_skill_attr(Skills,[]),
	TotalAttr   = util:combine_list(SkillAttr++CellAttrs++EquipAttr),
	PartialAttr = attr_conv:to_attr_record(TotalAttr),
	Power = lib_player_attr:calc_attr_power_partial(AttrPower, BaseAttr, PartialAttr),
	NewPower = Power+SPower,
	NCellFoster = CellFoster#cell_foster{combat=NewPower},
    NewNeedUpdate =
    if OldCombat =/= NewPower ->
            [CellType|NeedUpdate];
        true -> NeedUpdate
    end,
	calc_foster_power(Status,AttrPower,BaseAttr,T,[NCellFoster|Fosters], NewNeedUpdate,SkillPower+SPower).

get_foster_power(Player, Type) ->
	case Player#player_status.role_foster of
		#role_foster{fosters=Fosters} ->
			case lists:keyfind(Type, #cell_foster.type, Fosters) of
				#cell_foster{combat = Power} -> Power;
				_ -> 0
			end;
		_ ->
			0
	end.

filter_open(Lv)->
	All =?ALL_FOSTER,
	filter_open(Lv,All,[]).
filter_open(_,[],All)->
	All;
filter_open(Lv,[H|T],All)->
	case Lv>=data_module:get_module_open_lv(?MOD_FOSTER,H) of
		true->
			TaskId = data_module:get_sub_pre_task_id(?MOD_FOSTER,H),
			case lib_role_task:is_finish_task_id(TaskId) of
				true->
					 filter_open(Lv,T,[H|All]);
				false when TaskId=<0->
					 filter_open(Lv,T,[H|All]);
				_->
					 filter_open(Lv,T,All)
			end;
		_->
			filter_open(Lv,T,All)
	end.

%% 使用直升丹物品，直接升阶/升星
use_stuff_up_fosters(Status, GoodsInfo, GoodsNum)->
	#player_status{id=RoleID,role_foster = RoleFoster}=Status,
    CheckL = [
        {is_foster_goods_efftect_cfg, GoodsInfo#goods.goods_id},
        {foster_goods_num, GoodsInfo#goods.num, GoodsNum}
    ],
    case util:check_lists(?MODULE,CheckL) of
        true ->
            #role_foster{fosters = CellFosters} = RoleFoster,
            #goods_effect{effect_list = [{OpTy, FosterCell, MaxValue, ReBacks}|_]} = data_goods_effect:get(GoodsInfo#goods.goods_id),
	        IsGradeType = lists:member(FosterCell, ?GRADE_FOSTER),
            case OpTy of
            	foster_grade_up when IsGradeType -> %%直接进阶
		            case lists:keyfind(FosterCell, #cell_foster.type, CellFosters) of
		                CellFoster = #cell_foster{grade = CellGrade} ->
							lib_goods_api:cost_object_list(Status, [{0, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
		                    NewStatus = if CellGrade > MaxValue ->
		                            Produce = #produce{type = role_foster, reward=ReBacks},
            						lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER),
            						Status;
		                        true ->
		                            use_stuff_up_foster_grade(CellGrade+1, CellFoster, Status)
		                    end,
		                    {ok, NewStatus, GoodsNum};
		                _ ->
		                    {fail, ?FAIL}
		            end;
		        foster_star_up when IsGradeType ->
		        	case lists:keyfind(FosterCell, #cell_foster.type, CellFosters) of
		                CellFoster = #cell_foster{grade = CellGrade} ->
							lib_goods_api:cost_object_list(Status, [{0, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
		                    NewStatus = if CellGrade > MaxValue ->
		                            Produce = #produce{type = role_foster, reward=ReBacks},
            						lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER),
            						Status;
		                        true ->
		                            use_stuff_up_foster_star(CellFoster, Status)
		                    end,
		                    {ok, NewStatus, GoodsNum};
		                _ ->
		                    {fail, ?FAIL}
		            end;
		        _ ->
		        	{fail,?FAIL}
		    end;
        {false, ErrCode} ->
            {fail, ErrCode}
    end.

%% 使用进阶直升丹 -- 升星
use_stuff_up_foster_star(CellFoster, Player) ->
    #player_status{id = RoleID, role_foster = RoleFoster} = Player,
    #role_foster{fosters = CellFosters} = RoleFoster,
    #cell_foster{type = Type, grade = OldGrade, star = OldStar} = CellFoster,
    #base_foster{clear = IsClear,next_grade=NextGrade,next_star=NextStar} = data_foster:get_base_foster(Type, OldGrade, OldStar),
    NewCellFoster = CellFoster#cell_foster{
        grade = NextGrade, star = NextStar, exp = 0,
        click = 0, clear = IsClear,
        display = NextGrade, etime = utime:unixtime()
    },
    #cell_foster{grade = NewGrade, star = NewStar} = NewCellFoster,
    NCellFoster = lib_role_foster:after_foster_up(true, RoleID, NewCellFoster),
    #base_foster{award = Awards} = data_foster:get_base_foster(Type, NewGrade, NewStar),
    lib_role_foster:update_role_foster(main,RoleID,NCellFoster),
    NFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NCellFoster),
    NewPlayer  = Player#player_status{role_foster = RoleFoster#role_foster{fosters=NFosters}},
    if Awards /= []->
            Produce = #produce{type = role_foster, reward=Awards},
            lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER);
        true ->
            skip
    end,

    NewPlayer2 = lib_role_foster:count_foster_attr(NewPlayer),
    NewPlayer3 = lib_player:count_player_attribute(NewPlayer2),
    lib_player:send_attribute_change_notify(NewPlayer3, ?NOTIFY_ATTR),
    update_foster_attr_to_scene(NewPlayer3, Type),
    mod_scene_agent:update(NewPlayer3,[{battle_attr, NewPlayer3#player_status.battle_attr}]),

	%% 最新形象通知场景
	NewPlayer4 = lib_role_foster:update_role_figure(NewPlayer3),
	Figure4 = NewPlayer4#player_status.figure,
	mod_scene_agent:update(NewPlayer4, [{role_foster, Figure4#figure.role_foster}]),

    {ok, Bin0}  = pt_146:write(14601, [?SUCCESS, 0, 0, 0, Type, NewGrade, NewStar, 1, 0]),
    Bin1 = lib_role_foster:pack_14600(Type, NewPlayer3),
    Bin  = <<Bin0/binary,Bin1/binary>>,
    lib_server_send:send_to_uid(RoleID, Bin),

	lib_achievement_api:foster_skill_event(NewPlayer3, calc_foster_skills(NFosters)),
	%% 脱下其他外观
	lib_player:apply_cast(RoleID, ?APPLY_CAST_STATUS, lib_role_foster, put_off_other_appearance, [Type, 4, NextGrade]),

    lib_player_event:async_dispatch(RoleID, ?EVENT_FOSTER_GRADE_STAR_UP, {Type,NextGrade,NextStar}),
	NewPlayer4.

%% 使用进阶直升丹 -- 升阶
use_stuff_up_foster_grade(UpGrade, CellFoster, Player) ->
    #player_status{id = RoleID, role_foster = RoleFoster} = Player,
    #role_foster{fosters = CellFosters} = RoleFoster,
    #cell_foster{type = Type, grade = OldGrade, star = OldStar, exp = Exp} = CellFoster,
    #base_foster{clear = IsClear, max = Max} = data_foster:get_base_foster(Type, OldGrade, OldStar),
    NewCellFoster = CellFoster#cell_foster{
        grade = UpGrade, star = 0, exp = 0,
        click = 0, clear = IsClear,
        display = UpGrade, etime = utime:unixtime()
    },
    #cell_foster{grade = NewGrade, star = NewStar} = NewCellFoster,
    NCellFoster = lib_role_foster:after_foster_up(true, RoleID, NewCellFoster),

    #base_foster{next_grade=NextGrade,next_star=NextStar}=data_foster:get_base_foster(Type, OldGrade, OldStar),
    Awards = calc_awards(Type,NextGrade,NextStar,NewGrade,NewStar,[]),
    lib_role_foster:update_role_foster(main,RoleID,NCellFoster),
    NFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NCellFoster),
    NewPlayer  = Player#player_status{role_foster = RoleFoster#role_foster{fosters=NFosters}},
    if Awards /= []->
            Produce = #produce{type = role_foster, reward=Awards},
            lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER);
        true ->
            skip
    end,

    NewPlayer2 = lib_role_foster:count_foster_attr(NewPlayer),
    NewPlayer3 = lib_player:count_player_attribute(NewPlayer2),
    lib_player:send_attribute_change_notify(NewPlayer3, ?NOTIFY_ATTR),
    update_foster_attr_to_scene(NewPlayer3, Type),
    mod_scene_agent:update(NewPlayer3,[{battle_attr, NewPlayer3#player_status.battle_attr}]),

	%% 最新形象通知场景
	NewPlayer4 = lib_role_foster:update_role_figure(NewPlayer3),
	Figure4 = NewPlayer4#player_status.figure,
	mod_scene_agent:update(NewPlayer4, [{role_foster, Figure4#figure.role_foster}]),

    {ok, Bin0}  = pt_146:write(14601, [?SUCCESS, 0, 0, 0, Type, NewGrade, NewStar, 1, Max-Exp]),
    Bin1 = lib_role_foster:pack_14600(Type, NewPlayer3),
    Bin  = <<Bin0/binary,Bin1/binary>>,
    lib_server_send:send_to_uid(RoleID, Bin),

	lib_achievement_api:foster_skill_event(NewPlayer4, calc_foster_skills(NFosters)),
	%% 脱下其他外观
	lib_player:apply_cast(RoleID, ?APPLY_CAST_STATUS, lib_role_foster, put_off_other_appearance, [Type, 4, UpGrade]),

    lib_player_event:async_dispatch(RoleID, ?EVENT_FOSTER_GRADE_UP, {Type,NewGrade}),

	NewPlayer4.

calc_awards(Type,NewGrade,NewStar,NewGrade,NewStar,OAwards)->
	case  data_foster:get_base_foster(Type, NewGrade, NewStar) of
		#base_foster{award = Awards}->
			util:combine_list(OAwards++Awards,1);
		_->
			util:combine_list(OAwards,1)
	end;
calc_awards(Type,OldGrade,OldStar,NewGrade,NewStar,OAwards)->
	case  data_foster:get_base_foster(Type, OldGrade, OldStar) of
		#base_foster{award = Awards,next_grade=NextGrade,next_star=NextStar}->
			calc_awards(Type,NextGrade,NextStar,NewGrade,NewStar,OAwards++Awards);
		_->
			util:combine_list(OAwards,1)
	end.


%% return - [{skill_id, lv}...]
calc_foster_skills(Fosters) ->
	F = fun(#cell_foster{skills = Skills}, TList) ->
		[{SkillId, Lv}||{_, Lv, SkillId}<-Skills] ++ TList
	    end,
	lists:foldl(F, [], Fosters).

%%获取被动技能
get_foster_passive_skill(Status)->
	#player_status{role_foster = RoleFoster} = Status,
    #role_foster{fosters = CellFosters} = RoleFoster,
    F = fun(#cell_foster{skills = Skills}, TList) ->
		[{SkillId, Lv}||{_, Lv, SkillId}<-Skills] ++ TList
	    end,
	Skills = lists:foldl(F, [], CellFosters),
	lib_skill:divide_passive_skill(Skills).

%% ---------------------------------------------------------------------------
%% @doc 更新培养系统属性到场景
-spec update_foster_attr_to_scene(Role, Type) -> ok when
    Role        :: #player_status{},
    Type        :: integer().
%% ---------------------------------------------------------------------------
update_foster_attr_to_scene(Role, ?FJARVIS) ->
    BattleAttr = get_foster_battle_attr(Role, partner_battle_attr),
    mod_scene_agent:update(Role, [{partner_battle_attr, BattleAttr}]),
    ok;
update_foster_attr_to_scene(Role, ?FPEARL) ->
    BattleAttr = get_foster_battle_attr(Role, baby_battle_attr),
    mod_scene_agent:update(Role, [{baby_battle_attr, BattleAttr}]),
    ok;
update_foster_attr_to_scene(_Role, _Type) ->
    ok.


%% ---------------------------------------------------------------------------
%% @doc 获取某个培养系统的战斗属性
-spec get_foster_battle_attr(Role, Type) -> AttrList when
    Role        :: #player_status{},
    Type        :: integer() | atom(),
    AttrList    :: [{AttrId :: integer(), Value :: integer()}].
%% ---------------------------------------------------------------------------
get_foster_battle_attr(Role, partner_battle_attr) ->
    AttrList = get_foster_attr(Role, ?FJARVIS),
    Attr = attr_conv:to_attr_record(AttrList),
    #battle_attr{attr = Attr};
get_foster_battle_attr(Role, baby_battle_attr) ->
    AttrList = get_foster_attr(Role, ?FPEARL),
    Attr = attr_conv:to_attr_record(AttrList),
    #battle_attr{attr = Attr};
get_foster_battle_attr(_Role, _Type) ->
    #battle_attr{}.


%% ---------------------------------------------------------------------------
%% @doc 获取某个培养系统的属性
-spec get_foster_attr(Role, Type) -> AttrList when
    Role        :: #player_status{},
    Type        :: integer() | atom(),
    AttrList    :: [{AttrId :: integer(), Value :: integer()}].
%% ---------------------------------------------------------------------------
get_foster_attr(Role, partner_battle_attr) ->
    get_foster_attr(Role, ?FJARVIS);
get_foster_attr(Role, baby_battle_attr) ->
    get_foster_attr(Role, ?FPEARL);
get_foster_attr(Role, Type) ->
    #player_status{role_foster = #role_foster{fosters = Fosters}} = Role,
    case lists:keyfind(Type, #cell_foster.type, Fosters) of
        #cell_foster{attrs = Attrs, skill_attr = SkillAttr, equip_attr = EquipAttr} ->
            util:combine_list(Attrs ++ SkillAttr ++ EquipAttr);
        _ ->
            []
    end.


%% ---------------------------------------------------------------------------
%% @doc 检查玩家是否已学习了指定技能
-spec check_have_learn_skill(Role, SkillId, Type) -> true | false when
    Role        :: #player_status{},
    SkillId     :: integer(),
    Type        :: atom().
%% ---------------------------------------------------------------------------
check_have_learn_skill(Role, SkillId, partner_battle_attr) ->
    check_have_learn_skill(Role, SkillId, ?FJARVIS);
check_have_learn_skill(Role, SkillId, baby_battle_attr) ->
    check_have_learn_skill(Role, SkillId, ?FPEARL);
check_have_learn_skill(Role, SkillId, Type) ->
    #player_status{role_foster = #role_foster{fosters = Fosters}} = Role,
    case lists:keyfind(Type, #cell_foster.type, Fosters) of
        #cell_foster{skills = SkillList,base_skill=BaseSkill} ->
            case lists:keyfind(SkillId, 3, [{0,1,BaseSkill}|SkillList]) of
                {_Pos, _Lev, SkillId} -> true;
                _ -> false
            end;
        _ ->
            false
    end.

%% @doc 所有外观更新相关的都要调用这个接口 @end
update_role_figure(Status)->
	update_role_figure(true,Status).
update_role_figure(IsUpdate,Status)->
	#player_status{figure=Figure,role_foster=RoleFoster}=Status,
    #role_foster{fosters=Fosters}=RoleFoster,
    Shows = [{Type,Dis}||#cell_foster{type=Type,display=Dis}<-Fosters],
    case lists:keyfind(?FHORSE,#cell_foster.type,Fosters) of
		#cell_foster{state=IsRide} ->
			skip;
		_->
			IsRide = 0
	end,
	FosterSubSkins = lib_role_foster_skin:get_sub_foster_skin_figure(Status),
    Figure0 = Figure#figure{is_ride=IsRide,role_foster=Shows,foster_sub_skin=FosterSubSkins},
	NFigure = update_lv_model(Figure0),
    IsUpdate andalso lib_role:update_role_show(Status#player_status.id, [{figure,NFigure}]),
	Status#player_status{figure=NFigure}.

update_lv_model(Figure)->
	#figure{
		lv_model = LvModel0,
		role_foster = Fosters,
		career = Carrer
	}=Figure,
	LvModel = update_lv_model([?FWING,?FWEAPON],Carrer,Fosters,LvModel0),
	Figure#figure{lv_model=LvModel}.

update_lv_model([],_Carrer,_Fosters,LvModel)->
	LvModel;
update_lv_model([H|T],Carrer,Fosters,LvModel)->
	case lists:keyfind(H,1,Fosters) of
		{_,Grade}->
			case data_foster:get_base_foster(H,Grade,0) of
				#base_foster{resource=Res}->
					Res;
				_->
					Res = 0
			end;
		_->
			Res = 0
	end,
	Pos = case H of
		?FWING->
			5;
		?FWEAPON->
			2;
		_->
			0
	end,
	Show = case H of
		?FWEAPON->
			util:ceil(Carrer*1000+Res);
		_->
			Res
	end,
	NLvModel = case Pos>0 of
		true->
			lists:keystore(Pos,1,LvModel,{Pos,Show});
		_->
			LvModel
	end,
	update_lv_model(T,Carrer,Fosters,NLvModel).


get_base_skill(?FJARVIS)->?FJARVIS_SKILL;
get_base_skill(?FPEARL)->?FPEARL_SKILL;
get_base_skill(_)->0.


%%按照位置查找道具
get_pos_goods(Type,Grade,Pos)->
	AllGoods = get_all_equip_list(Type),
	do_get_pos_goods(Grade,Pos,AllGoods).
do_get_pos_goods(Grade,Pos,AllGoods)->
	GEquips = [G||G<-AllGoods,G#goods.cell=:=Pos],
	filter_grade(GEquips,Grade).

filter_grade([],_)->
	undefind;
filter_grade([H|T],Grade)->
	#goods{extra_data=Extras}=H,
	case lists:keyfind(?GOODS_OTHER_KEY_FOSTER_GRADE,1,Extras) of
		{_,Grade}->
			H;
		_->
			filter_grade(T,Grade)
	end.

%% 获得所有装备 list 格式返回
get_all_equip_list(Type) ->
    GoodsStatus = lib_goods_do:get_goods_status(),
    get_all_equip_list(Type,GoodsStatus).
get_all_equip_list(Type,GoodsStatus) ->
	LocEquip = case Type of
        ?FHORSE->
            ?GOODS_LOC_FHORSE_EQUIP_BAG;
        ?FJARVIS->
            ?GOODS_LOC_FJARVIS_EQUIP_BAG;
        _->
            0
    end,
    lib_goods_util:get_goods_list(GoodsStatus#goods_status.dict, LocEquip).


%% 特殊事件(已废弃)
special_event(Type,Status)->
	#player_status{
        id = RoleID,
        figure=#figure{name=Name},
        scene = Scene,
        scene_pool_id = PoolID,
        copy_id = CopyId,
        x = X, y = Y,
        role_foster=RoleFoster
    } = Status,
    #role_foster{fosters=Fosters}=RoleFoster,
	case lists:keyfind(Type,#cell_foster.type,Fosters) of
		#cell_foster{grade=Grade,star=Star,exp=Exp,etime=ETime}=Foster when Grade=<1->
			#base_foster{max=Max,next_grade=NGrade} = data_foster:get_base_foster(Type,Grade,Star),
			NFoster = Foster#cell_foster{
				grade  = NGrade,
				display= NGrade,
				exp = Exp+50-Max
			},
			IsU = true,
            NCellFoster = lib_role_foster:after_foster_up(IsU,RoleID,NFoster),
            #base_foster{award=Awards,is_tv=IsTv} = data_foster:get_base_foster(Type,NGrade,Star),
            lib_role_foster:update_role_foster(main,RoleID,NCellFoster),
            NFosters = lists:keystore(Type,#cell_foster.type,Fosters,NFoster),
            Status1  = Status#player_status{role_foster = RoleFoster#role_foster{fosters=NFosters}},
            case IsU of
                true when Awards /= []->
                    Produce = #produce{type=role_foster,reward=Awards},
                    lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER);
                _->
                    skip
            end,
            Status2 = lib_role_foster:update_role_figure(Status1),
            Status3 = lib_role_foster:count_foster_attr(Status2),
            Status4 = lib_player:count_player_attribute(Status3),
            lib_player:send_attribute_change_notify(Status4, ?NOTIFY_ATTR),
            lib_role_foster:update_foster_attr_to_scene(Status4, Type),

            {ok, Bin0}  = pt_146:write(14601, [?SUCCESS,0,Type,NGrade,Star,1,50]),
            Bin1 = lib_role_foster:pack_14600(Type,Status4),
            Bin  = <<Bin0/binary,Bin1/binary>>,
            lib_server_send:send_to_uid(RoleID,Bin),

            Figure4 = Status4#player_status.figure,
            mod_scene_agent:update(Status4,[{role_foster,Figure4#figure.role_foster}]),
            {ActiveType, KeyValues} = lib_role_foster:calc_all_foster(Type, NFosters),

            {ok, Status5} = lib_wardrobe_active:active_foster(Status4, ActiveType, KeyValues, [Type, NGrade]),
            IsTv>0 andalso lib_chat:send_TV({all}, ?MOD_FOSTER, Type, [Name,RoleID,NGrade]),
            %%场景广播
            {ok, Bin2} = pt_120:write(12016, [?MOD_FOSTER,Type,RoleID,NGrade]),
            lib_server_send:send_to_area_scene(Scene,PoolID,CopyId,X,Y,Bin2),
            lib_player_event:async_dispatch(RoleID, ?EVENT_FOSTER_GRADE_UP, {Type,NGrade}),
            mod_scene_agent:update(Status5, [{battle_attr, Status5#player_status.battle_attr}]),
            lib_rush_rank_api:refresh_rank_by_foster(Type,Status4),
            LogData = [
                RoleID,Name,Type,NGrade,Star,Exp,ETime,0
                ,util:term_to_string([]),utime:unixtime()
            ],
            lib_log_api:log_foster_upgrade(LogData),
            lib_task_api:foster_lv_up(Status5,Type),
			lib_achievement_api:foster_skill_event(Status5, calc_foster_skills(NFosters)),
            Status5;
        #cell_foster{grade=Grade,star=Star}->
        	#base_foster{cost=Cost} = data_foster:get_base_foster(Type,Grade,Star),
        	Awards = [{T,K,10}||{T,K,_V}<-Cost],
        	Awards0 = [{K,10}||{_T,K,_V}<-Cost],
        	Produce = #produce{type = role_foster, reward=Awards},
            lib_goods_api:send_reward_with_mail(RoleID, Produce, ?MOD_FOSTER),
            {ok,Bin} = pt_146:write(14613,[Type,Grade,Star,Awards0]),
            lib_server_send:send_to_uid(RoleID,Bin),
			Status
	end.

calc_equip_assist_active(Type, Grade, Assist, GradeEquips) ->
    case equip_attr_access(Type, Grade, GradeEquips) of
        true ->
            NewAssist = if Assist == 0 -> 1;
                true -> Assist
            end,
            NewAssist;
        false ->
            NewAssist =
            if Assist == 1 orelse Assist == 2 -> 0;
                true -> Assist
            end,
            NewAssist
    end.

equip_attr_access(Type, Grade, Equips) ->
    EquipNum = length(Equips),
    if EquipNum >= 6 ->
            case data_foster:get_foster_assist_num(Type, Grade) of
                [{Color, NeedNum}|_] ->
                    equip_attr_access_logic(Equips, {Color, NeedNum}, 0);
                _ ->
                    false
            end;
        true -> false
    end.

equip_attr_access_logic([], {_, NeedNum}, Num) ->
    Num >= NeedNum;
equip_attr_access_logic([#foster_equip{color = EquipColor}|Rest], {Color, NeedNum}, Num) ->
    if
        EquipColor >= Color ->
            equip_attr_access_logic(Rest, {Color, NeedNum}, Num+1);
        true ->
            equip_attr_access_logic(Rest, {Color, NeedNum}, Num)
    end.

%% --------------------------------------------------------------------------------------------
%% @doc 弱进阶系统 @end
%% 弱进阶系统升级
sub_foster_up(Player, Type, MaterialType, IsAuto) ->
	#player_status{id = RoleId, sid = Sid, role_foster = RoleFoster, figure = Figure
	} = Player,
	#role_foster{fosters = CellFosters} = RoleFoster,
	%% 初始默认1级
	CellFoster =
	case lists:keyfind(Type, #cell_foster.type, CellFosters) of
		#cell_foster{} = TCellFoster -> TCellFoster;
		_ -> #cell_foster{type = Type, grade = 0, lv = 1}
	end,
	#cell_foster{grade = Grade, lv = OldLv, exp = Exp} = CellFoster,
	CheckList = [{check_max_lv, Type, OldLv}, {check_material_cfg, Type}, {check_material_type, MaterialType, IsAuto}],
	case check_sub_foster_up(CheckList) of
		true ->
			#base_foster_sub_material{primary_material = [{PriGood, PriExp}],
				middle_material = [{MidGood, MidExp}], senior_material = [{SenGood, SenExp}]} =
					data_foster:get_foster_sub_material(Type),
			[{_, OwnNum1}] = lib_goods_api:get_goods_num(Player, [PriGood]),
			[{_, OwnNum2}] = lib_goods_api:get_goods_num(Player, [MidGood]),
			[{_, OwnNum3}] = lib_goods_api:get_goods_num(Player, [SenGood]),
			%% 自动升级，消耗材料从低级到高级
			{CostGood, AddExp} =
			case IsAuto of
				1 ->
					if
						OwnNum1 > 0 ->
							{PriGood, PriExp};
						OwnNum2 > 0 ->
							{MidGood, MidExp};
						OwnNum3 > 0 ->
							{SenGood, SenExp};
						true ->
							%% 材料不够由物品接口去检测
							{PriGood, PriExp}
					end;
				_ ->
					case MaterialType of
						?PRIMARY_TYPE ->{PriGood, PriExp};
						?MIDDLE_TYPE -> {MidGood, MidExp};
						?SENIOR_TYPE -> {SenGood, SenExp};
						_ -> {PriGood, PriExp}
					end
			end,
			CostList = [{?TYPE_GOODS, CostGood, 1}],
			case lib_goods_api:cost_object_list_with_check(Player, CostList, sub_foster_lv_up, "") of
				{false, Err, _} ->
					lib_server_send:send_to_sid(Sid, pt_146, 14620, [Err, Type, MaterialType, OldLv, Exp]),
					{ok, Player};
				{true, Player1, _} ->
					{NewLv, NewExp} = calc_new_lv(Type, OldLv, Exp, AddExp),
					CellFoster1 = CellFoster#cell_foster{lv = NewLv, exp = NewExp, display=1},
					NewCellFoster = lib_role_foster:after_foster_up(NewLv =/= OldLv, RoleId, CellFoster1),
					lib_role_foster:update_role_foster(main, RoleId, NewCellFoster),
					NewCellFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NewCellFoster),
					NewRoleFoster = RoleFoster#role_foster{fosters = NewCellFosters},
					Player2 = Player1#player_status{role_foster = NewRoleFoster},
					Player3 = lib_role_foster:count_foster_attr(Player2),
					Player4 = lib_player:count_player_attribute(Player3),
					lib_player:send_attribute_change_notify(Player4, ?NOTIFY_ATTR),
					mod_scene_agent:update(Player4, [{battle_attr, Player4#player_status.battle_attr}]),
					lib_server_send:send_to_sid(Sid, pt_146, 14620, [?SUCCESS, Type, MaterialType, NewLv, Exp]),

					%% 自动幻化
					Player4p = lib_role_foster:update_role_figure(Player4),
					LFigure = Player4p#player_status.figure,
					mod_scene_agent:update(Player4p,[{role_foster, LFigure#figure.role_foster}]),

					%% TODO: 一些场景的更新和任务的处理
					lib_role_foster:update_foster_attr_to_scene(Player4p, Type),
					case NewLv =/= OldLv of
						true ->
							lib_player_event:async_dispatch(RoleId, ?EVENT_FOSTER_LV_UP, {Type,NewLv}),
							send_sub_foster_tv(RoleId, Figure#figure.name, Type, OldLv, NewLv);
						_ ->
							ignore
					end,
					%% 等级记录在star里面
					LogData = [
						RoleId, Figure#figure.name,Type, Grade, NewLv, NewExp, 0, 0,
						util:term_to_string(CostList), utime:unixtime()
					],
					lib_log_api:log_foster_upgrade(LogData),
					lib_seven_days_goal:finish_task(RoleId, ?MOD_FOSTER, Type, NewLv, true),
					lib_achievement_api:foster1_event(Player4p, [{Type, NewLv}]),
					{ok, Player4p}
			end;
		{false, ErrCode} ->
			lib_server_send:send_to_sid(Sid, pt_146, 14620, [ErrCode, Type, MaterialType, OldLv, Exp]),
			{ok, Player}
	end.

send_sub_foster_tv(RoleId, Name, Type, OldLv, NewLv) ->
	F = fun(TLv) ->
		case TLv rem 10 == 0 of
			true ->
				lib_chat:send_TV({all}, ?MOD_FOSTER, 11,
					[Name, RoleId, get_foster_tv_name(Type), TLv]
				);
			_ ->
				ignore
		end end,
	lists:map(F, lists:seq(OldLv+1, max(OldLv+1, NewLv))),
	ok.

get_foster_tv_name(Type) ->
	case Type of
		5 -> "AI希亚";
		6 -> "光子磁炮";
		7 -> "光子星翼";
		8 -> "光子幻甲";
		_ -> "AI希亚"
	end.

calc_new_lv(Type, OldLv, Exp, AddExp) ->
	NeedExp = get_lv_up_exp_need(Type, OldLv),
	SumExp  = Exp+AddExp,
	%% 有可能连续升级
	case SumExp >= NeedExp of
		true -> do_add_exp(Type, OldLv, SumExp);
		_ -> {OldLv, SumExp}
	end.

do_add_exp(Type, FosterLv, SumExp) ->
	NeedExp = get_lv_up_exp_need(Type, FosterLv),
	if
		NeedExp > 0 andalso SumExp >= NeedExp ->
			LeftExp  = SumExp - NeedExp,
			NewFosterLv = FosterLv + 1,
			do_add_exp(Type, NewFosterLv, LeftExp);
		true ->
			{FosterLv, SumExp}
	end.

get_lv_up_exp_need(Type, FosterLv) ->
	case data_foster:get_foster_lv(Type, FosterLv) of
		#base_foster_sub{need_exp = NeedExp} -> NeedExp;
		_ -> 0
	end.

%% @doc 弱进阶系统皮肤 @end
%% 皮肤信息
sub_foster_skin_info(Player, Type) ->
	#player_status{sid = Sid, role_foster = RoleFoster} = Player,
	#role_foster{fosters = CellFosters} = RoleFoster,
	%% 如果弱进阶还没有激活，先初始化数值
	CellFoster = case lists:keyfind(Type, #cell_foster.type, CellFosters) of
		             #cell_foster{} = TCellFoster -> TCellFoster;
		             _ -> #cell_foster{type = Type, grade = 0, lv = 0}
	             end,
	#cell_foster{skin_list = SkinList} = CellFoster,
	F = fun(SkinInfo, TList) ->
		case SkinInfo of
			#sub_cell_foster_skin{skin_id = SkinId, star = Star, display_star = DisplayStar} ->
				[{SkinId, Star, DisplayStar}|TList];
			_ ->
				TList
		end end,
	PackList = lists:foldl(F, [], SkinList),
	lib_server_send:send_to_sid(Sid, pt_146, 14617, [Type, PackList]),
	{ok, Player}.

%% 激活/升级皮肤
upgrade_sub_foster_skin(Player, Type, SkinId, Option) ->
	#player_status{id = RoleId, sid = Sid, role_foster = RoleFoster, figure = Figure} = Player,
	#role_foster{fosters = CellFosters} = RoleFoster,
	%% 如果弱进阶还没有激活，先初始化数值
	CellFoster = case lists:keyfind(Type, #cell_foster.type, CellFosters) of
		             #cell_foster{} = TCellFoster -> TCellFoster;
		             _ -> #cell_foster{type = Type, grade = 0, lv = 0}
	             end,
	#cell_foster{skin_list = SkinList} = CellFoster,
	CellFosterSkin =
	case lists:keyfind(SkinId, #sub_cell_foster_skin.skin_id, SkinList) of
		#sub_cell_foster_skin{} = TCellFosterSkin -> TCellFosterSkin;
		_ -> #sub_cell_foster_skin{skin_id = SkinId}
	end,
	#sub_cell_foster_skin{star = OldStar, display_star = DisplayStar} = CellFosterSkin,
	CheckList = [{check_skin_max, Type, SkinId, OldStar}, {check_material, Type, SkinId, OldStar}],
	case check_sub_foster_skin(CheckList) of
		{false, ErrCode} ->
			lib_server_send:send_to_sid(Sid, pt_146, 14618, [ErrCode, Type, SkinId, Option, OldStar]),
			{ok, Player};
		_ ->
			#base_foster_sub_skin{cost_material = CostList, name = SkinName} =
				data_foster:get_foster_sub_skin(Type, SkinId, OldStar),
			case lib_goods_api:cost_object_list_with_check(Player, CostList, sub_foster_skin_up, "") of
				{true, Player1, _} ->
					NewStar = OldStar + 1,
					NewCellFosterSkin = CellFosterSkin#sub_cell_foster_skin{star = NewStar},
					NewSkinList    = lists:keystore(SkinId, #sub_cell_foster_skin.skin_id, SkinList,NewCellFosterSkin),
					NewCellFoster  = CellFoster#cell_foster{skin_list = NewSkinList},
					NewCellFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NewCellFoster),
					NewRoleFoster  = RoleFoster#role_foster{fosters = NewCellFosters},
					%% 存库
					DbInfo = [Type, SkinId, NewStar, DisplayStar],
					lib_role_foster:update_role_foster(sub_foster_skin, RoleId, DbInfo),
					%% 属性 和 场景数据
					Player2 = Player1#player_status{role_foster = NewRoleFoster},
					{ActiveType, KeyValues} = lib_role_foster:calc_all_foster(Type, NewCellFosters),
					{ok, Player3} = lib_wardrobe_active:active_foster(Player2, ActiveType, KeyValues, [Type, NewStar]),
					Player4 = lib_role_foster:count_foster_attr(Player3),
					NewPlayer = lib_player:count_player_attribute(Player4),
					lib_player:send_attribute_change_notify(NewPlayer, ?NOTIFY_ATTR),
					mod_scene_agent:update(NewPlayer, [{battle_attr, NewPlayer#player_status.battle_attr}]),
					lib_server_send:send_to_sid(Sid, pt_146, 14618, [?SUCCESS, Type, SkinId, Option, NewStar]),
					%% 传闻
					case NewStar of
						1 -> lib_chat:send_TV({all}, ?MOD_FOSTER, 12, [Figure#figure.name, RoleId, SkinName]);
						_ -> lib_chat:send_TV({all}, ?MOD_FOSTER, 13, [Figure#figure.name, RoleId, SkinName, NewStar])
					end,
					LogData = [RoleId, Figure#figure.name,Type, Option, SkinId, OldStar, NewStar,
						util:term_to_string(CostList), utime:unixtime()],
					lib_log_api:log_foster_skin_upgrade(LogData),
					{ok, NewPlayer};
				{false, Err, _Player1} ->
					lib_server_send:send_to_sid(Sid, pt_146, 14618, [Err, Type, SkinId, Option, OldStar]),
					{ok, Player}
			end
	end.

%% 幻化皮肤
use_foster_skin(Player, Type, SkinId, DisplayStar) ->
	#player_status{id = RoleId, sid = Sid, role_foster = RoleFoster
		,scene = SceneId, scene_pool_id = PoolId, copy_id = CopyId, x = X, y = Y
	} = Player,
	#role_foster{fosters = CellFosters} = RoleFoster,
	%% 如果弱进阶还没有激活，先初始化数值
	CellFoster = case lists:keyfind(Type, #cell_foster.type, CellFosters) of
		             #cell_foster{} = TCellFoster -> TCellFoster;
		             _ -> #cell_foster{type = Type, grade = 0, lv = 0}
	             end,
	#cell_foster{skin_list = SkinList} = CellFoster,
	CellFosterSkin =
		case lists:keyfind(SkinId, #sub_cell_foster_skin.skin_id, SkinList) of
			#sub_cell_foster_skin{} = TCellFosterSkin -> TCellFosterSkin;
			_ -> #sub_cell_foster_skin{skin_id = SkinId}
		end,
	%% 是否已经激活该星级
	CheckList = [{has_active, SkinId, SkinList, DisplayStar}],
	case check_sub_foster_skin(CheckList) of
		{false, ErrCode} ->
			lib_server_send:send_to_sid(Sid, 14619, [ErrCode, Type, SkinId, DisplayStar]),
			{ok, Player};
		_ ->
			#sub_cell_foster_skin{star = Star} = CellFosterSkin,
			NewCellFosterSkin = CellFosterSkin#sub_cell_foster_skin{display_star = DisplayStar},
			%% 清理缓存内单个类型所有幻化的数据
			SkinList1 = clear_used_skin(SkinList, SkinList),
			NewSkinList = lists:keystore(SkinId, #sub_cell_foster_skin.skin_id, SkinList1, NewCellFosterSkin),
			SkinId1 = case DisplayStar of 0 -> 0; _ -> SkinId end,
			NewCellFoster  = CellFoster#cell_foster{skin_list = NewSkinList, display_skin = {SkinId1, DisplayStar}},
			NewCellFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NewCellFoster),
			NewRoleFoster  = RoleFoster#role_foster{fosters = NewCellFosters},
			DbInfo = [Type, SkinId, Star, DisplayStar],
			%% 先清理原来幻化的
			case DisplayStar of
				0 ->
					F = fun() ->
						reset_foster_display_skin(RoleId, Type), ok
					end;
				_ ->
					F = fun() ->
						reset_foster_display_skin(RoleId, Type),
						lib_role_foster:update_role_foster(sub_foster_skin, RoleId, DbInfo),
						ok end
			end,
			case catch db:transaction(F) of
				ok ->
					%% 属性 和 场景数据
					Player1 =
					case DisplayStar > 0 of
						true -> put_off_other_appearance(Player, Type, 3, {SkinId1, DisplayStar});
						_ ->
							%% 直接推送场景协议
							{ok, Bin1} = pt_120:write(12016, [?MOD_FOSTER, Type+2000, RoleId, util:term_to_string({SkinId1, DisplayStar})]),
							lib_server_send:send_to_area_scene(SceneId, PoolId, CopyId, X, Y, Bin1),
							Player
					end,
					FosterFigure = lib_role_foster_skin:get_sub_foster_skin_figure(Player1#player_status{role_foster = NewRoleFoster}),
					mod_scene_agent:update(Player1, [{foster_sub_skin, FosterFigure}]),
					Figure1 = Player1#player_status.figure,
					NewFigure = Figure1#figure{foster_sub_skin = FosterFigure},
					lib_role:update_role_show(RoleId, [{figure, NewFigure}]),
					NewPlayer = Player1#player_status{role_foster = NewRoleFoster, figure = NewFigure},
					lib_server_send:send_to_sid(Sid, pt_146, 14619, [?SUCCESS, Type, SkinId, DisplayStar]),
					{ok, NewPlayer};
				_ ->
					lib_server_send:send_to_sid(Sid, pt_146, 14619, [?FAIL, Type, SkinId, DisplayStar]),
					{ok, Player}
			end
	end.

clear_used_skin([], ClearSkinList) -> ClearSkinList;
clear_used_skin([CellSkin|T], SkinList) ->
	case CellSkin of
		#sub_cell_foster_skin{skin_id = SkinId} ->
			NewSkinList = lists:keystore(SkinId, #sub_cell_foster_skin.skin_id,
				SkinList, CellSkin#sub_cell_foster_skin{display_star = 0});
		_ ->
			NewSkinList = SkinList
	end,
	clear_used_skin(T, NewSkinList).

reset_foster_display_skin(RoleId, Type) ->
	Sql = io_lib:format(?SQL_PLAYER_SUB_FOSTER_SKIN_UPDATE, [RoleId, Type]),
	db:execute(Sql),
	ok.

check_sub_foster_up([]) -> true;
check_sub_foster_up([Check|L]) ->
	case do_check_sub_foster_up(Check) of
		true -> check_sub_foster_up(L);
		{false, Res} -> {false, Res}
	end.

do_check_sub_foster_up({check_max_lv, Type, OldLv}) ->
	case data_foster:get_foster_lv(Type, OldLv) of
		#base_foster_sub{next_attr = []} ->
			{false, ?ERRCODE(err146_foster_max_lv)};
		#base_foster_sub{} ->
			true;
		_ ->
			{false, ?ERRCODE(err146_foster_type_err)}
	end;
do_check_sub_foster_up({check_material_cfg, Type}) ->
	case data_foster:get_foster_sub_material(Type) of
		#base_foster_sub_material{
			primary_material = [{_,_}],middle_material = [{_, _}],senior_material = [{_, _}]} -> true;
		_ -> {false, ?ERRCODE(err146_sub_foster_material_err)}
	end;
do_check_sub_foster_up({check_material_type, MaterialType, IsAuto}) ->
	case IsAuto of
		1 -> true;
		_ ->
			case lists:member(MaterialType, ?MATERIAL_ALL_TYPE) of
				true -> true;
				_ -> {false, ?ERRCODE(err146_material_type_err)}
			end
	end;
do_check_sub_foster_up(_Check) ->
	?ERR("<<Error do_check_sub_foster_up>>"),
	{false, ?FAIL}.


check_sub_foster_skin([]) -> true;
check_sub_foster_skin([Check|L]) ->
	case do_check_sub_foster_skin(Check) of
		true -> check_sub_foster_skin(L);
		{false, Res} -> {false, Res}
	end.
do_check_sub_foster_skin({has_active, SkinId, SkinList, Star}) ->
	case lists:keyfind(SkinId, #sub_cell_foster_skin.skin_id, SkinList) of
		#sub_cell_foster_skin{star = ActiveStar} ->
			case ActiveStar >= Star of
				true -> true;
				_ -> {false, ?ERRCODE(err146_sub_foster_star_not_enough)}
			end;
		_ -> {false, ?ERRCODE(err146_sub_foster_skin_has_no_active)}
	end;
do_check_sub_foster_skin({check_skin_max, Type, SkinId, Star}) ->
	case data_foster:get_foster_sub_skin(Type, SkinId, Star) of
		#base_foster_sub_skin{next_star = NextStar} when NextStar =/= 0 -> true;
		_ -> {false, ?ERRCODE(err146_foster_skin_max)}
	end;
do_check_sub_foster_skin({check_material, Type, SkinId, Star}) ->
	case data_foster:get_foster_sub_skin(Type, SkinId, Star) of
		#base_foster_sub_skin{cost_material = CostMaterial} ->
			case CostMaterial of
				[_|_] -> true;
				_ -> {false, ?ERRCODE(err146_foster_skin_material_err)}
			end;
		_ ->
			{false, ?ERRCODE(err146_foster_skin)}
	end;
do_check_sub_foster_skin(_Check) ->
	?ERR("<<Error do_check_sub_foster_skin>>"),
	{false, ?FAIL}.


%% 卸下该位置的外观(注意是多数是同步操作，先卸下旧的，再穿戴新的)
%% Type:位置  AppearanceType:幻化的外观类型   1-时装 2-珍宝 3-皮肤 4-基础模型
%% OtherData: 12016具体要推送的数据
put_off_other_appearance(Player, Type, AppearanceType, OtherData) ->
	#player_status{
		id = RoleId, role_foster_skin = RoleSkin, role_foster = RoleFoster
		,scene = SceneId, scene_pool_id = PoolId, copy_id = CopyId, x = X, y = Y
	} = Player,
	#role_foster{fosters = TypeFosters} = RoleFoster,
	#role_foster_skin{fosters = FostersSkins} = RoleSkin,

	{FosterType, FashionType} = case lists:member(AppearanceType, [2,3,4]) of
		                            true -> {Type, change_to_fashion_type(Type)};
		                            _ -> {change_to_foster_type(Type), Type}
	                            end,

	%% 时装(只需要处理背饰和武器)
	{_, WearFashion} = lib_fashion:get_equip_fashion_list(Player),
	Player1 =
	case lists:keyfind(FashionType, 1, WearFashion) of
		{_, FashionId, _} when AppearanceType =/= 1  ->
			put_off_fashion(Player, FashionType, FashionId);
		_ -> Player
	end,

	%% 进阶珍宝(穿非珍宝时需要卸下)
	SkinId = get_used_skin(lists:keyfind(FosterType, #cell_foster_skin.type, FostersSkins)),
	Player2 =
	case SkinId > 0 of
		true when AppearanceType =/= 2 ->
			put_off_skin(Player1, FosterType, 0, 0);
		_ -> Player1
	end,

	%% 进阶皮肤(穿非皮肤时需要卸下)
	SubSkinId = get_used_sub_skin(lists:keyfind(FosterType, #cell_foster.type, TypeFosters)),
	Player3 =
	case SubSkinId > 0 of
		true when AppearanceType =/= 3 ->
			put_off_sub_skin(Player2, FosterType, SubSkinId, 0);
		_ -> Player2
	end,

	%% 进阶(非进阶幻化时需要卸下，注意是强进阶才需要卸下)  -- 进阶基础模型不卸下了
	% FosterGrade = get_used_foster(lists:keyfind(FosterType, #cell_foster.type, TypeFosters)),
	% case FosterGrade > 0 of
	% 	true when AppearanceType =/= 4 , FosterType =< 4 ->
	%		IsAlive andalso RolePid ! {'proto', 14603, [FosterType, 0]};
	% 	_ -> ignore
	% end,

	%% 场景推送
	case AppearanceType of
		2 ->
			{ok, Bin1} = pt_120:write(12016, [?MOD_FOSTER, Type+1000, RoleId, util:term_to_string(OtherData)]),
			lib_server_send:send_to_area_scene(SceneId, PoolId, CopyId, X, Y, Bin1);
		3 ->
			{ok, Bin1} = pt_120:write(12016, [?MOD_FOSTER, Type+2000, RoleId, util:term_to_string(OtherData)]),
			lib_server_send:send_to_area_scene(SceneId, PoolId, CopyId, X, Y, Bin1);
		4 ->
			{ok, Bin1} = pt_120:write(12016, [?MOD_FOSTER, Type, RoleId, OtherData]),
			lib_server_send:send_to_area_scene(SceneId, PoolId, CopyId, X, Y, Bin1);
		_ ->
			ignore
	end,

	Player3.

%% @doc 统一抽离脱下外观代码 @end
%% 为了前端方便，处理一遍脱下代码吧，跟协议发起逻辑代码类似，只是去掉了检查逻辑
%% 1> 脱下珍宝
put_off_skin(Player, Type, SkinID, Star) -> % SkinId = 0, Star = 0
	#player_status{id = RoleID, role_foster_skin = RoleSkin} = Player,
	#role_foster_skin{fosters = Fosters} = RoleSkin,
	case lib_role_foster_skin:change_display(RoleID,Type,SkinID,Star, Fosters) of
		{ok, IsUpdate, NCellFoster}->
			#cell_foster_skin{display={CurSkin,CurStar}}=NCellFoster,
			{ok, Bin} = pt_146:write(14612,[?SUCCESS,Type,CurSkin,CurStar]),
			lib_server_send:send_to_uid(RoleID,Bin),

			NFosters = lists:keystore(Type,#cell_foster_skin.type,Fosters,NCellFoster),
			NewPlayer = Player#player_status{role_foster_skin = RoleSkin#role_foster_skin{fosters=NFosters}},
			FosterFigure = lib_role_foster_skin:get_foster_skin_figure(NewPlayer),
			IsUpdate andalso mod_scene_agent:update(NewPlayer, [{foster_skin,FosterFigure}]),
			Figure1 = Player#player_status.figure,
			NFigure = Figure1#figure{foster_skin=FosterFigure},
			lib_role:update_role_show(RoleID, [{figure,NFigure}]),

			NewPlayer#player_status{figure=NFigure};
		{false, Err}->
			{ok, Bin} = pt_146:write(14612,[Err,Type,SkinID,Star]),
			lib_server_send:send_to_uid(RoleID,Bin),
			Player
	end.

%% 2> 脱下皮肤
put_off_sub_skin(Player, Type, SkinId, DisplayStar) ->
	#player_status{id = RoleId, sid = Sid, role_foster = RoleFoster
	} = Player,
	#role_foster{fosters = CellFosters} = RoleFoster,
	%% 如果弱进阶还没有激活，先初始化数值
	CellFoster = case lists:keyfind(Type, #cell_foster.type, CellFosters) of
		             #cell_foster{} = TCellFoster -> TCellFoster;
		             _ -> #cell_foster{type = Type, grade = 0, lv = 0}
	             end,
	#cell_foster{skin_list = SkinList} = CellFoster,
	CellFosterSkin =
		case lists:keyfind(SkinId, #sub_cell_foster_skin.skin_id, SkinList) of
			#sub_cell_foster_skin{} = TCellFosterSkin -> TCellFosterSkin;
			_ -> #sub_cell_foster_skin{skin_id = SkinId}
		end,
	NewCellFosterSkin = CellFosterSkin#sub_cell_foster_skin{display_star = DisplayStar},
	%% 清理缓存内单个类型所有幻化的数据
	SkinList1 = clear_used_skin(SkinList, SkinList),
	NewSkinList = lists:keystore(SkinId, #sub_cell_foster_skin.skin_id, SkinList1, NewCellFosterSkin),
	SkinId1 = case DisplayStar of 0 -> 0; _ -> SkinId end,
	NewCellFoster  = CellFoster#cell_foster{skin_list = NewSkinList, display_skin = {SkinId1, DisplayStar}},
	NewCellFosters = lists:keystore(Type, #cell_foster.type, CellFosters, NewCellFoster),
	NewRoleFoster  = RoleFoster#role_foster{fosters = NewCellFosters},
	reset_foster_display_skin(RoleId, Type),
	FosterFigure = lib_role_foster_skin:get_sub_foster_skin_figure(Player#player_status{role_foster = NewRoleFoster}),
	mod_scene_agent:update(Player, [{foster_sub_skin, FosterFigure}]),
	Figure1 = Player#player_status.figure,
	NewFigure = Figure1#figure{foster_sub_skin = FosterFigure},
	lib_role:update_role_show(RoleId, [{figure, NewFigure}]),
	NewPlayer = Player#player_status{role_foster = NewRoleFoster, figure = NewFigure},
	lib_server_send:send_to_sid(Sid, pt_146, 14619, [?SUCCESS, Type, SkinId, DisplayStar]),
	NewPlayer.

%% 3> 脱下时装
put_off_fashion(Player, PosId, FashionId) ->
	#player_status{id = RoleId, sid = Sid, role_fashion = RoleFashion
	} = Player,
	#role_fashion{all_fashions = AllFashions} = RoleFashion,
	#fashion_pos{fashion_list = FashionList} = FashionPos = lib_fashion:get_fashion_pos(PosId, AllFashions),
	FashionInfo = lib_fashion:get_fashion_info(PosId, FashionId, FashionList),
	NewFashionInfo = FashionInfo#fashion_info{color_id = 0},
	NewFashionPos = FashionPos#fashion_pos{wear_fashion_id = 0, wear_color_id = 0},
	lib_fashion:db_update_fashion_info(RoleId, NewFashionInfo),
	lib_fashion:db_update_fashion_pos(RoleId, NewFashionPos),
	NewAllFashions = lib_fashion:update_fashion_info(NewFashionInfo, FashionList, NewFashionPos, AllFashions),
	NewRoleFashion = RoleFashion#role_fashion{all_fashions = NewAllFashions},
	NewPlayer = Player#player_status{role_fashion = NewRoleFashion},
	%% 更新场景玩家时装
	NewPlayer1 = lib_fashion:update_role_scene_fashion_info(NewPlayer, 0, 0, 0),
	lib_server_send:send_to_sid(Sid, pt_413, 41303, [?SUCCESS, PosId, FashionId]),
	NewPlayer1.

%% 获取该类型幻化的珍宝
get_used_skin(CellFosterSkin) ->
	case CellFosterSkin of
		#cell_foster_skin{display = {DisPlaySkin, _}} -> DisPlaySkin;
		_ -> 0
	end.

%% 获取该类型幻化的皮肤
get_used_sub_skin(CellFoster) ->
	case CellFoster of
		#cell_foster{display_skin = {DisPlaySkin, _}} -> DisPlaySkin;
		_ -> 0
	end.

%% 获取改类型幻化的进阶
get_used_foster(CellFoster) ->
	case CellFoster of
		#cell_foster{display = DisplayGrade} -> DisplayGrade;
		_ -> 0
	end.

%% 进阶类型转时装位置
change_to_fashion_type(Type) ->
	case Type of
		2 -> 3;
		4 -> 4;
		_ -> 0
	end.

%% 时装位置转进阶类型
change_to_foster_type(Type) ->
	case Type of
		3 -> 2;
		4 -> 4;
		_ -> 0
	end.