%%%--------------------------------------
%%% @Module  : lib_live_skill
%%% @Author  : zzy
%%% @Created : 2018-10-17
%%% @Description:  生活技能
%%%--------------------------------------
-module(lib_live_skill).

-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("goods.hrl").
-include("task.hrl").
-include("language.hrl").
-include("scene.hrl").
-include("def_fun.hrl").
-include("live_skill.hrl").
-include("predefine.hrl").
-include("def_goods.hrl").
-include("def_module.hrl").
-include("def_daily.hrl").
-include("def_event.hrl").
-include("rec_event.hrl").
-compile(export_all).
%% ---------------------------------- 登录 -----------------------------------
login(PS) ->
	#player_status{id = RoleId, figure = #figure{lv = RoleLv}} = PS,
	case db_select_live_skill(RoleId) of
		[] -> SkillList1 = [];
		List ->
			SkillList1 = [#live_skill{skill_type = SkillType, lv = Lv, exp = Exp} || [SkillType, Lv, Exp] <- List]
	end,
	%%获取钓鱼等级
	SkillList2 = case lib_fishing:get_fishing_lv_mastery(PS) of
		[FishLv, FishExp] -> [#live_skill{skill_type = ?TYPE_FISH_SKILL, lv = FishLv, exp = FishExp} | SkillList1];
		_ -> [ #live_skill{skill_type = ?TYPE_FISH_SKILL} | SkillList1]
	end,
	SkillList3 = init_produce_skill(PS, SkillList2),
	case db_select_live_skill_info(RoleId) of
		[] -> CookList = EquipList = [] ;
		[BitCookList, BitEquipList] ->
			CookList = util:bitstring_to_term(BitCookList),
			EquipList = util:bitstring_to_term(BitEquipList)
	end,
	SkillList4 = init_default_skill(SkillList3, RoleLv),
	StatusLiveSkill = #status_live_skill{skill_list = SkillList4, cook_list = CookList, equip_list = EquipList},
	PS#player_status{live_skill = StatusLiveSkill}.

%%初始化生产技能
init_produce_skill(_PS, SkillList) ->
	SkillList.

%%初始化默认技能
init_default_skill(SkillList, Lv) ->
	DefaultType = [?TYPE_COOK_SKILL],
	Fun = fun(SkillType, TmpList)->
		case lists:keyfind(SkillType, #live_skill.skill_type, TmpList) of
			false ->
				LiveSkill = #live_skill{skill_type = SkillType, lv = 1},
				if
					SkillType == ?TYPE_COOK_SKILL andalso Lv >= ?COOK_OPEN_LV ->
						[LiveSkill | TmpList];
					true -> TmpList
				end;
			_ -> TmpList
		end
	end,
	lists:foldl(Fun, SkillList, DefaultType).

%%技能界面
get_skill_list(PS) ->
	#player_status{live_skill = #status_live_skill{skill_list = SkillList}, sid = Sid} = PS,
	SkillTypes = data_live_skill:get_skill_types(),
	PackList = [{SkillType, SkillLv, SkillExp}|| #live_skill{skill_type = SkillType, lv = SkillLv, exp = SkillExp} <- SkillList],
	NotActiveList = [{SkillType, 0, 0} || SkillType <- SkillTypes, lists:keymember(SkillType, 1, PackList) == false],
	SendList = PackList ++ NotActiveList,
	{ok, Bin} = pt_435:write(43501, [SendList]),
	lib_server_send:send_to_sid(Sid, Bin).

%%烹饪(打造)界面
skill_handle_show(_PS, SkillType) when SkillType =/= ?TYPE_COOK_SKILL andalso SkillType =/= ?TYPE_EQUIP_SKILL-> skip;
skill_handle_show(PS, SkillType) ->
	#player_status{live_skill = #status_live_skill{skill_list = SkillList, cook_list = CookList, equip_list = EquipList}, sid = Sid} = PS,
	case lists:keyfind(SkillType, #live_skill.skill_type, SkillList) of
		false -> SkillLv = SkillExp = 0;
		#live_skill{lv = SkillLv, exp = SkillExp} -> ok
	end,
	BookList = ?IF(SkillType == ?TYPE_COOK_SKILL, CookList, EquipList),
	{ok, Bin} = pt_435:write(43502, [SkillType, SkillLv, SkillExp, 0, BookList]),
	lib_server_send:send_to_sid(Sid, Bin).

%% ---------------------------------- 烹饪(打造) -----------------------------------
skill_handle(PS, SkillType, TypeId) ->
	%%判断先暂时分开处理，统一处理扩展性差, 太多case if, 后续可优化
	if
		SkillType == ?TYPE_COOK_SKILL -> cook_handle(PS, SkillType, TypeId);
		SkillType == ?TYPE_EQUIP_SKILL -> equip_handle(PS, SkillType, TypeId);
		true -> {false, ?FAIL}
	end.

cook_handle(PS, SkillType, TypeId) ->
	#player_status{id = RoleId, live_skill = #status_live_skill{skill_list = SkillList, cook_list = CookList}, figure = #figure{lv = Lv}} = PS,
	CookCfg = data_live_skill:get_cook_type(TypeId),
	FoodIds = data_live_skill:get_food_ids(TypeId),
	SkillLvs = data_live_skill:get_food_lvs(TypeId),
	Live = lib_counter:get_count(RoleId, ?MOD_ACTIVITY, ?POWER_LIVE_DAILY),
	TmpCfg = ?IF(is_record(CookCfg, base_cook_type), CookCfg, #base_cook_type{}),
	CheckList = [
		{check_cfg, CookCfg, base_cook_type},
		{check_lv, Lv, ?COOK_OPEN_LV},
		{check_id_list, FoodIds, SkillType},
		{check_book, CookList, TypeId, TmpCfg#base_cook_type.good_id},
		{check_skill_lv, SkillList, SkillType, SkillLvs},
		{check_handle_cost, PS, TmpCfg#base_cook_type.cost, TmpCfg#base_cook_type.cost_live, Live},
		{check_bag_num, PS, FoodIds}
	],
	case check_list(CheckList) of
		true ->
			#base_cook_type{cost_live = CostLive, add_exp = AddExp, cost = Cost, time = Time} = CookCfg,
			CostType = lists:concat(["cook-type_id:", TypeId]),
			case common_cost(PS, Cost, CostType, CostLive, [], SkillType) of
				{true, NewPS} ->
					Args = [CostLive, AddExp, Live, TypeId, Time, Cost],
					do_handle(NewPS, SkillType, Args);
				{return, Err, _GoodsList} -> %%活力不足，扣了物品
					?ERR("cook_handle, return ~p~n",[{RoleId, TypeId, _GoodsList}]),
					{false, Err};
				{false, Err} -> {false, Err}
			end;
		{false, Err} -> {false, Err}
	end.

equip_handle(PS, SkillType, TypeId) ->
	#player_status{id = RoleId, live_skill = #status_live_skill{skill_list = SkillList, equip_list = EquipList}} = PS,
	FurnitureCfg = data_live_skill:get_furniture_type(TypeId),
	FurnitureIds = data_live_skill:get_furniture_ids(TypeId),
	SkillLvs = data_live_skill:get_furniture_lvs(TypeId),
	Live = lib_counter:get_count(RoleId, ?MOD_ACTIVITY, ?POWER_LIVE_DAILY),
	TmpCfg = ?IF(is_record(FurnitureCfg, base_furniture_type), FurnitureCfg, #base_furniture_type{}),
	CheckList = [
		{check_cfg, FurnitureCfg, base_furniture_type},
		{check_id_list, FurnitureIds, SkillType},
		{check_book, EquipList, TypeId, TmpCfg#base_furniture_type.good_id},
		{check_skill_lv, SkillList, SkillType, SkillLvs},
		{check_handle_cost, PS, TmpCfg#base_furniture_type.cost, TmpCfg#base_furniture_type.cost_live, Live}
	],
	case check_list(CheckList) of
		true ->
			#base_furniture_type{cost_live = CostLive, add_exp = AddExp, cost = Cost, cost_res = CostRes, time = Time} = FurnitureCfg,
			CostType = lists:concat(["furniture-type_id:", TypeId]),
			case common_cost(PS, Cost, CostType, CostLive, CostRes, SkillType) of
				{true, NewPS} ->
					Args = [CostLive, AddExp, Live, TypeId, Time, Cost],
					do_handle(NewPS, SkillType, Args);
				{return, Err, _GoodsList} -> %%活力不足，扣了物品
					?ERR("equip_handle, return ~p~n",[{RoleId, TypeId, _GoodsList}]),
					{false, Err};
				{false, Err} -> {false, Err}
			end;
		{false, Err} -> {false, Err}
	end.

%%扣除东西
common_cost(PS, Cost, CostType, CostLive, CostRes, SkillType) ->
	#player_status{id = RoleId} = PS,
	case lib_goods_api:cost_object_list(PS, Cost, live_skill, CostType) of
		{true, NewPS} ->
			case lib_activitycalen_api:cost_power_live(NewPS, CostLive, ?MOD_LIVE_SKILL, SkillType) of
				ok ->
					case lib_role_home_api:cost_res_list(NewPS, CostRes) of
						NewPS1 when is_record(NewPS1, player_status) ->
							{true, NewPS1};
						_ ->
							?ERR("equip_handle ERROR~p,~p~n",[RoleId, Cost]),
							?IF(Cost == [], {false, ?FAIL}, {return, ?FAIL, Cost})
					end;
				{false, Err} ->
					?IF(Cost == [], {false, Err}, {return, Err, Cost})
			end;
		{false, Err, _} -> {false, Err}
	end.

do_handle(PS, SkillType, Args) ->
	[CostLive, AddExp, _Live, TypeId, Time, Cost] = Args,
	#player_status{sid = Sid, id = RoleId, live_skill = StatusLiveSkill} = PS,
	#status_live_skill{skill_list = LiveSkillList} = StatusLiveSkill,
	LiveSkill = lists:keyfind(SkillType, #live_skill.skill_type, LiveSkillList),
	#live_skill{lv = Lv, exp = Exp} = LiveSkill,
	LvType = data_live_skill:get_lv_type(SkillType, Lv),
	{NewLv, NewExp} = lv_up(SkillType, Lv, Exp + AddExp),
	NewLiveSkill = LiveSkill#live_skill{lv = NewLv, exp = NewExp},
	db_replace_live_skill(RoleId, NewLiveSkill),
	NewLiveSkillList = lists:keystore(SkillType, #live_skill.skill_type, LiveSkillList, NewLiveSkill),
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{skill_list = NewLiveSkillList},
	NewPS = PS#player_status{live_skill = NewStatusLiveSkill},
	Fun = fun({Id, NeedLv, Weight}, TmpList)->
		RandWeight = lists:keyfind(LvType, 1, Weight),
		if
			Lv < NeedLv -> TmpList;
			RandWeight == false -> TmpList;
			true ->
				{_, RandW} = RandWeight,
				[{Id, RandW} | TmpList]
		end
	end,
	WeightList = get_weight_list(SkillType, TypeId),
	CanCookList = lists:foldl(Fun, [], WeightList),
	case CanCookList == [] of
		true -> LastPS = NewPS, Reward = [];
		false ->
			{GoodId, _} = util:find_ratio(CanCookList, 2),
			LastPS = send_reward(NewPS, SkillType, GoodId, Time, TypeId),
			Reward = [{?TYPE_GOODS, GoodId, 1}]
	end,
	{ok, Bin} = pt_435:write(43503, [?SUCCESS, SkillType, NewLv, NewExp, TypeId, Reward]),
	lib_server_send:send_to_sid(Sid, Bin),
	lib_log_api:log_live_skill_handle(RoleId, SkillType, Lv, AddExp, NewLv, CostLive, Cost, Reward),
	handle_after(LastPS, SkillType, [Lv, NewLv]),
	{true, LastPS}.

lv_up(SkillType, Lv, Exp)->
	NeedExp = data_live_skill:get_lv(SkillType, Lv),
	MaxLv = data_live_skill:get_max_lv(SkillType),
	case Exp >= NeedExp of
		true ->
			case Lv >= MaxLv of
				true-> {Lv,0};
				false-> lv_up(SkillType, Lv + 1, Exp - NeedExp)
			end;
		false-> {Lv, ?IF(Lv >= MaxLv, 0, Exp)}
	end.

send_reward(PS, ?TYPE_COOK_SKILL, GoodId, _Time, TypeId) ->
	% ShowTip = ?IF(Time >= 1, 0, 3),
	Reward = [{?TYPE_GOODS, GoodId, 1}],
	Remark = lists:concat(["cook-type_id:", TypeId]),
	Produce = #produce{title = utext:get(203), content = utext:get(204), type = live_skill, reward = Reward, show_tips = 0, remark = Remark},
	{ok, NewPS} = lib_goods_api:send_reward_with_mail(PS, Produce, ?MOD_LIVE_SKILL),
	NewPS;
send_reward(PS, ?TYPE_EQUIP_SKILL, GoodId, _Time, TypeId) ->
	IsMember = lists:member(TypeId, ?EQUIP_DATA_TYPE),
	%%材料类发成物品，家具类转换为家园内部数据
	case data_goods_type:get(GoodId) of
		#ets_goods_type{} when IsMember ->
			Reward = [{?TYPE_GOODS, GoodId, 1}],
			Remark = lists:concat(["furniture-type_id:", TypeId]),
			Produce = #produce{title = utext:get(203), content = utext:get(204), type = live_skill, reward = Reward, show_tips = 0, remark = Remark},
			{ok, NewPS} = lib_goods_api:send_reward_with_mail(PS, Produce, ?MOD_LIVE_SKILL);
		_ ->
			NewPS = PS
	end,
	NewPS.

%%获取[{NeedLv, Weight}]
get_weight_list(?TYPE_COOK_SKILL, TypeId) ->
	AllIds = data_live_skill:get_food_ids(TypeId),
	List = [data_live_skill:get_food(Id) || Id<- AllIds],
	[{FoodId, NeedLv, Weight} || #base_food{food_id = FoodId, need_lv = NeedLv, weight = Weight} <- List];
get_weight_list(?TYPE_EQUIP_SKILL, TypeId) ->
	AllIds = data_live_skill:get_furniture_ids(TypeId),
	List = [data_live_skill:get_furniture(Id) || Id<- AllIds],
	[{FurnitureId, NeedLv, Weight} || #base_furniture{furniture_id = FurnitureId, need_lv = NeedLv, weight = Weight} <- List].

handle_after(PS, ?TYPE_COOK_SKILL, [Lv, NewLv]) ->
	send_tv(PS, ?TYPE_COOK_SKILL, Lv, NewLv);
handle_after(PS, ?TYPE_EQUIP_SKILL, [Lv, NewLv]) ->
	send_tv(PS, ?TYPE_EQUIP_SKILL, Lv, NewLv);
handle_after(_, _, _) -> ok.

send_tv(PS, Type, Lv, NewLv) ->
	OldLvType = data_live_skill:get_lv_type(Type, Lv),
	NewLvType = data_live_skill:get_lv_type(Type, NewLv),
	?IF(OldLvType < NewLvType, do_send_tv(PS, Type, NewLv), ok).

do_send_tv(PS, Type, Lv) ->
	#player_status{figure = #figure{name = Name}} = PS,
	SkillName = data_live_skill:get_skill_name(Type),
	LvTypeName = data_live_skill:get_lv_type_name(Type, Lv),
	lib_chat:send_TV({all}, ?MOD_LIVE_SKILL, 1, [Name, SkillName, Lv, LvTypeName]).
%% ---------------------------------- 公共函数 -----------------------------------
%% 外部模块通知更新生活技能
%% return #player_status{}
notify_skill_change(PS, ?TYPE_EQUIP_SKILL, _Lv, _Exp) ->
	#player_status{id = RoleId, live_skill = StatusLiveSkill} = PS,
	#status_live_skill{skill_list = SkillList} = StatusLiveSkill,
	SkillType = ?TYPE_EQUIP_SKILL,
	case lists:keyfind(SkillType, #live_skill.skill_type, SkillList) of
		#live_skill{lv = 0} = OldLiveSkill ->    %%打造坊开启，技能默认1级
			NewLiveSkill = OldLiveSkill#live_skill{lv = 1},
			db_replace_live_skill(RoleId, NewLiveSkill),
			NewSkillList = lists:keystore(SkillType, #live_skill.skill_type, SkillList, NewLiveSkill);
		_ -> NewSkillList = SkillList
	end,
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{skill_list = NewSkillList},
	PS#player_status{live_skill = NewStatusLiveSkill};
notify_skill_change(PS, SkillType, Lv, Exp) ->
	#player_status{id = _RoleId, live_skill = StatusLiveSkill} = PS,
	#status_live_skill{skill_list = SkillList} = StatusLiveSkill,
	case lists:keyfind(SkillType, #live_skill.skill_type, SkillList) of
		false -> NewSkillList = SkillList;
		#live_skill{} = OldLiveSkill ->
			NewLiveSkill = OldLiveSkill#live_skill{lv = Lv, exp = Exp},
			NewSkillList = lists:keystore(SkillType, #live_skill.skill_type, SkillList, NewLiveSkill)
	end,
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{skill_list = NewSkillList},
	PS#player_status{live_skill = NewStatusLiveSkill}.

%% 使用食谱
use_cook_book(PS, GoodsInfo) ->
	#player_status{live_skill = StatusLiveSkill} = PS,
	#status_live_skill{cook_list = CookList} = StatusLiveSkill,
	#goods{goods_id = GoodId} = GoodsInfo,
	case data_live_skill:get_type_by_good_id(GoodId) of
		[TypeId|_T] when is_integer(TypeId) andalso TypeId > 0->
			case lists:member(TypeId, CookList) of
				true -> {fail, ?ERRCODE(err435_has_cook_book)};
				false -> do_use_cook_book(PS, StatusLiveSkill, TypeId)
			end;
		_ -> {fail, ?ERRCODE(err435_not_cook_book)}
	end.

do_use_cook_book(PS, StatusLiveSkill, TypeId) ->
	#status_live_skill{cook_list = CookList} = StatusLiveSkill,
	NewCookList = [TypeId | CookList],
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{cook_list = NewCookList},
	db_replace_live_skill_info(PS#player_status.id, NewStatusLiveSkill),
	NewPS = PS#player_status{live_skill = NewStatusLiveSkill},
	skill_handle_show(NewPS, ?TYPE_COOK_SKILL),
	{ok, NewPS}.

%% 使用食物增益
eat_food(PS, GoodsInfo, GoodsNum) ->
	#goods{goods_id = GoodId} = GoodsInfo,
    case data_goods:get_effect_list(GoodId) of
    	[] -> {fail, ?ERRCODE(err435_not_gain_food)};
    	_BuffEffectList ->
    		lib_goods_buff:add_goods_buff(PS#player_status.id, GoodId, GoodsNum, []),
    		{ok, PS}
    end.

%%使用打造纸
use_equip_paper(PS, GoodsInfo) ->
	#player_status{live_skill = StatusLiveSkill} = PS,
	#status_live_skill{equip_list = EquipList} = StatusLiveSkill,
	#goods{goods_id = GoodId} = GoodsInfo,
	case data_live_skill:get_equip_type_by_good_id(GoodId) of
		[TypeId|_T] when is_integer(TypeId) andalso TypeId > 0->
			case lists:member(TypeId, EquipList) of
				true -> {fail, ?ERRCODE(err435_has_equip_paper)};
				false -> do_use_equip_paper(PS, StatusLiveSkill, TypeId)
			end;
		_ -> {fail, ?ERRCODE(err435_not_equip_paper)}
	end.

do_use_equip_paper(PS, StatusLiveSkill, TypeId) ->
	#status_live_skill{equip_list = EquipList} = StatusLiveSkill,
	NewEquipList = [TypeId | EquipList],
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{equip_list = NewEquipList},
	db_replace_live_skill_info(PS#player_status.id, NewStatusLiveSkill),
	NewPS = PS#player_status{live_skill = NewStatusLiveSkill},
	skill_handle_show(NewPS, ?TYPE_EQUIP_SKILL),
	{ok, NewPS}.
%% ---------------------------------- 事件处理 -----------------------------------
handle_event(PS, #event_callback{type_id = ?EVENT_LV_UP}) when is_record(PS, player_status) ->
    #player_status{live_skill = StatusLiveSkill, figure = #figure{lv = Lv}} = PS,
    #status_live_skill{skill_list = SkillList} = StatusLiveSkill,
    SkillList1 = init_default_skill(SkillList, Lv),
    NewStatusLiveSkill = StatusLiveSkill#status_live_skill{skill_list = SkillList1},
    NewPS = PS#player_status{live_skill = NewStatusLiveSkill},
    {ok, NewPS};
handle_event(PS, _) ->
	{ok, PS}.

%% ---------------------------------- 检测 -----------------------------------
check_list([]) -> true;
check_list([H|T]) ->
    case check(H) of
        true -> check_list(T);
        {false, Res} ->
        	{false, Res}
    end.

check({check_lv, Lv, OpenLv}) ->
	case Lv >= OpenLv of
		true-> true;
		false -> {false, ?ERRCODE(err435_lv_not_enough)}
	end;
check({check_cfg, Cfg, Atom}) ->
	?IF(is_record(Cfg, Atom), true, {false, ?ERRCODE(err435_cfg_error)});%%配置异常
check({check_id_list, Ids, SkillType}) ->
	ErrCode = ?IF(SkillType == ?TYPE_COOK_SKILL, ?ERRCODE(err435_not_can_cook), ?ERRCODE(err435_not_can_equip)),
	?IF(Ids =/= [], true, {false, ErrCode}); %%没有可烹饪的
check({check_build_lv, _BuildMap, _BuildType, _Lv, _ActiveGoodId}) -> %%用食谱激活不用判断
	true;
check({check_book, _BookList, _TypeId, 0}) -> true;
check({check_book, BookList, TypeId, _GoodId}) ->
	case lists:member(TypeId, BookList) of
		false -> {false, ?ERRCODE(err435_not_active)};
		true -> true
	end;
check({check_skill_lv, LiveSkill, SkillType, SkillLvs}) ->
	SkillLvList = ?IF(SkillLvs == [], [0], SkillLvs),
	MinLv = lists:min(SkillLvList),
	case lists:keyfind(SkillType, #live_skill.skill_type, LiveSkill) of
		#live_skill{lv = Lv} when Lv >= MinLv -> true;
		_ -> {false, ?ERRCODE(err435_skill_lv_not_enough)} %%技能等级不够
	end;
check({check_handle_cost, PS, Cost, LiveCost, Live}) ->
	IsCost = check({check_cost, PS, Cost}),
	if
		Live < LiveCost -> {false, ?ERRCODE(err435_power_live_not_enough)}; %%活力不足
		IsCost =/= true -> IsCost;
		true -> true
	end;
check({check_bag_num, PS, FoodIds}) ->
	GoodTypeId = hd(FoodIds),
	case lib_goods_api:can_give_goods(PS, [{?TYPE_GOODS, GoodTypeId, 1}]) of
		true-> true;
		false ->
			{false, ?ERRCODE(err416_bag_no_null_cell)}
	end;
check({check_cost, PS, Cost}) ->
	lib_goods_api:check_object_list(PS, Cost);
check(_Msg)->
	{false, ?FAIL}.

%% ---------------------------------- db -----------------------------------
db_select_live_skill(RoleId) ->
	Sql = io_lib:format(?sql_select_live_skill, [RoleId]),
	db:get_all(Sql).

db_replace_live_skill(RoleId, LiveSkill) ->
	#live_skill{skill_type = SkillType, lv = Lv, exp = Exp } = LiveSkill,
	Sql = io_lib:format(?sql_replace_live_skill, [RoleId, SkillType, Lv, Exp]),
	db:execute(Sql).

db_select_live_skill_info(RoleId) ->
	Sql = io_lib:format(?sql_select_live_skill_info, [RoleId]),
	db:get_row(Sql).

db_replace_live_skill_info(RoleId, StatusLiveSkill) ->
	#status_live_skill{cook_list = CookList, equip_list = EquipList} = StatusLiveSkill,
	StringCookList = util:term_to_bitstring(CookList),
	StringEquipList = util:term_to_bitstring(EquipList),
	Sql = io_lib:format(?sql_replace_live_skill_info, [RoleId, StringCookList, StringEquipList]),
	db:execute(Sql).

%% ---------------------------------- 秘籍 -----------------------------------
gm_set_lv(PS, SkillType, SkillLv, Exp) ->
	#player_status{live_skill = StatusLiveSkill} = PS,
	#status_live_skill{skill_list = SkillList} = StatusLiveSkill,
	LiveSkill = #live_skill{skill_type = SkillType, lv = SkillLv, exp = Exp},
	NewSkillList = lists:keystore(SkillType, #live_skill.skill_type, SkillList, LiveSkill),
	NewStatusLiveSkill = StatusLiveSkill#status_live_skill{skill_list = NewSkillList},
	PS#player_status{live_skill = NewStatusLiveSkill}.
