You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
486 lines
18 KiB
486 lines
18 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using ProtoCSStruct;
|
|
using Sog;
|
|
|
|
namespace Game
|
|
{
|
|
/// <summary>
|
|
///抽卡系统
|
|
/// </summary>
|
|
public static class RecruitSvc
|
|
{
|
|
public static void OnEnter(PlayerOnGame player)
|
|
{
|
|
ref var recruitData = ref player.RoleData.RecruitData;
|
|
foreach (var kv in GachaDescMgr.Instance.ItemTable)
|
|
{
|
|
var desc = kv.Value;
|
|
var index = -1;
|
|
|
|
for (int i = 0; i < recruitData.Count; i++)
|
|
{
|
|
if (recruitData[i].PoolId == desc.InternalId)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index > -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var data = new RecruitData() { PoolId = desc.InternalId, RecruitCount = 0 };
|
|
for (var i = 0; i < (int)CommonQuality.Size - 1; i++)
|
|
{
|
|
data.Record.Add(0); //why do : find all quality records
|
|
}
|
|
|
|
recruitData.Add(data);
|
|
}
|
|
|
|
SyncData(player);
|
|
}
|
|
public static void RecruitChooseRewardReq(PlayerOnGame player, StructPacket packet)
|
|
{
|
|
ref var req = ref packet.GetMessage<CSRecruitRewardReq>();
|
|
var poolId = req.PoolId;
|
|
var res = new CSRecruitRewardRes();
|
|
res.PoolId = poolId;
|
|
res.ChooseId = req.ChooseId;
|
|
res.ChooseIndex = req.ChooseIndex;
|
|
ref var recruitData = ref player.RoleData.RecruitData;
|
|
var index = -1;
|
|
for (var i = 0; i < recruitData.Count; i++)
|
|
{
|
|
if (recruitData[i].PoolId == poolId)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 0)
|
|
{
|
|
return ;
|
|
}
|
|
ref var data = ref player.RoleData.RecruitData[index];
|
|
for(int i = 0; i < data.ChoseReward.Count; i++)
|
|
{
|
|
if (data.ChoseReward[i] == req.ChooseId)
|
|
{
|
|
res.Ret = -1;
|
|
player.SendToClient((int)CSGameMsgID.RecruitChooseRewardRes, ref res);
|
|
return;
|
|
}
|
|
}
|
|
var desc = GachaChooseRewardDescMgr.Instance.GetConfigByInternal(req.ChooseId);
|
|
if (desc == null)
|
|
{
|
|
res.Ret = -1;
|
|
player.SendToClient((int)CSGameMsgID.RecruitChooseRewardRes, ref res);
|
|
return;
|
|
}
|
|
if(desc.gachaNum < data.TotalCount)
|
|
{
|
|
res.Ret = -1;
|
|
player.SendToClient((int)CSGameMsgID.RecruitChooseRewardRes, ref res);
|
|
return;
|
|
}
|
|
data.TotalCount -= desc.gachaNum;
|
|
data.ChoseReward.Add(req.ChooseId);
|
|
var addItemId = desc.rewardId[req.ChooseIndex];
|
|
var unifyOp = new UnifyOp(player, BillChangeItemReason.Recruit);
|
|
unifyOp.AddGoods(desc.rewardType, addItemId, 1);
|
|
unifyOp.DoOp(true, true, true);
|
|
res.Ret = 0;
|
|
res.Data.CopyFrom(ref data);
|
|
player.SendToClient((int)CSGameMsgID.RecruitChooseRewardRes, ref res);
|
|
|
|
}
|
|
//抽卡入口
|
|
public static void Recruit(PlayerOnGame player, StructPacket packet)
|
|
{
|
|
ref var req = ref packet.GetMessage<RecruitReq>();
|
|
var poolId = req.PoolId;
|
|
var cmd = (int)CSGameMsgID.RecruitRes;
|
|
var res = new RecruitRes();
|
|
if (req.RecruitCount <= 0 || req.PoolId <= 0)
|
|
{
|
|
res.Ret = (int)CSErrCode.DescNotFound;
|
|
player.SendToClient(cmd, ref res);
|
|
return;
|
|
}
|
|
|
|
var desc = GachaDescMgr.Instance.GetConfigByInternal(poolId);
|
|
if (desc == null)
|
|
{
|
|
res.Ret = (int)CSErrCode.DescNotFound;
|
|
player.SendToClient(cmd, ref res);
|
|
return;
|
|
}
|
|
|
|
if (desc.unlockId != 0 && !SystemUnlockSvc.IsUnlockSys(player, desc.unlockId))
|
|
{
|
|
res.Ret = (int)CSErrCode.SysUnlocked;
|
|
player.SendToClient(cmd, ref res);
|
|
return;
|
|
}
|
|
|
|
var cost = new IDStringValue();
|
|
var ret = RecruitCost(player, poolId, req.RecruitCount, false, ref cost);
|
|
if (ret != CSErrCode.None)
|
|
{
|
|
res.Ret = (int)CSErrCode.DescNotFound;
|
|
player.SendToClient(cmd, ref res);
|
|
return;
|
|
}
|
|
|
|
var unifyOp = new UnifyOp(player, BillChangeItemReason.Recruit);
|
|
List<TypeIDValueString> result = new List<TypeIDValueString>();
|
|
for (var i = 0; i < req.RecruitCount; i++)
|
|
{
|
|
RecruitOne(player, unifyOp, req.PoolId, result);
|
|
}
|
|
|
|
var list = new List<CSItemChgInfo>();
|
|
unifyOp.DoOp(sendGetItemMsg: false, retList: list);
|
|
for (var i = 0; i < list.Count; i++)
|
|
{
|
|
var count = list[i].ChgCount;
|
|
if (list[i].Type != (int)GoodsType.Gem)
|
|
{
|
|
res.Rewards.Add(list[i]);
|
|
}
|
|
else
|
|
{
|
|
//宝石需要裁开显示
|
|
for (var j = 0; j < count; j++)
|
|
{
|
|
var reward = new CSItemChgInfo();
|
|
var r = list[i];
|
|
reward.CopyFrom(ref r);
|
|
reward.ChgCount = 1;
|
|
if (res.Rewards.Count >= res.Rewards.GetMaxCount())
|
|
{
|
|
player.SendToClient(cmd, ref res);
|
|
res.Rewards.Clear();
|
|
}
|
|
|
|
res.Rewards.Add(reward);
|
|
}
|
|
}
|
|
}
|
|
|
|
SyncData(player);
|
|
PopPackageSvc.TriggerPopPackage(player,PackPopType.Gacha);
|
|
GameTALogUtils.Recruit(player, 1, (int)desc.type, req.RecruitCount, cost, result);
|
|
if (res.Rewards.Count > 0)
|
|
{
|
|
player.SendToClient(cmd, ref res);
|
|
}
|
|
}
|
|
|
|
//看广告给抽卡
|
|
public static void RecruitAdv(PlayerOnGame player, int poolId)
|
|
{
|
|
var cmd = (int)CSGameMsgID.RecruitRes;
|
|
var res = new RecruitRes();
|
|
var unifyOp = new UnifyOp(player, BillChangeItemReason.RecruitAdv);
|
|
var cost = new IDStringValue();
|
|
RecruitCost(player, poolId, 1, true, ref cost);
|
|
List<TypeIDValueString> result = new List<TypeIDValueString>();
|
|
RecruitOne(player, unifyOp, poolId, result);
|
|
unifyOp.DoOp(sendGetItemMsg: true);
|
|
var desc = GachaDescMgr.Instance.GetConfigByInternal(poolId);
|
|
GameTALogUtils.Recruit(player, 1, (int)desc.type, 1, cost, result);
|
|
SyncData(player);
|
|
PopPackageSvc.TriggerPopPackage(player,PackPopType.Gacha);
|
|
player.SendToClient(cmd, ref res);
|
|
}
|
|
|
|
//抽一次
|
|
public static CSErrCode RecruitOne(PlayerOnGame player, UnifyOp unifyOp, int poolId,
|
|
List<TypeIDValueString> result)
|
|
{
|
|
var desc = GachaDescMgr.Instance.GetConfigByInternal(poolId);
|
|
var cmd = (int)CSGameMsgID.RecruitRes;
|
|
var res = new RecruitRes();
|
|
if (desc == null)
|
|
{
|
|
return CSErrCode.DescNotFound;
|
|
}
|
|
|
|
ref var recruitData = ref player.RoleData.RecruitData;
|
|
var index = -1;
|
|
for (var i = 0; i < recruitData.Count; i++)
|
|
{
|
|
if (recruitData[i].PoolId == poolId)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 0)
|
|
{
|
|
return CSErrCode.DescNotFound;
|
|
}
|
|
string rewardId = "";
|
|
int maxQualityIndex = 0;
|
|
ref var data = ref recruitData[index];
|
|
data.SpCount++;
|
|
data.TotalCount++;
|
|
bool sp = false;
|
|
if (data.SpCount >= desc.spguaranteedTimes && desc.spguaranteedTimes > 0)
|
|
{
|
|
rewardId = desc.spguaranteedReward;
|
|
sp = true; }
|
|
else
|
|
{
|
|
data.RecruitCount++;
|
|
rewardId = GetRecruitRewardId(player, ref data, desc, out maxQualityIndex);
|
|
//找到抽卡抽到上限制的最高品质
|
|
TraceLog.Trace("Recruit.RecruitOne uid={0} recruit rewardId={1} ,guaranteed quality={2}",
|
|
player.UserID, rewardId, maxQualityIndex + 1);
|
|
}
|
|
|
|
//发奖
|
|
SendRecruitReward(player, unifyOp, rewardId, out var maxQualityVal, result);
|
|
bool hasSp = false;
|
|
foreach(var r in result)
|
|
{
|
|
if (r.Type == desc.spguaranteedType && maxQualityVal == (int)desc.spguaranteedQuality)
|
|
{
|
|
hasSp = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hasSp)
|
|
{
|
|
data.SpCount = 0;
|
|
TraceLog.Trace("Recruit.RecruitOne uid={0} get sp rewardId={1} ",
|
|
player.UserID, rewardId );
|
|
}
|
|
if (sp)
|
|
{
|
|
data.SpCount = 0;
|
|
TraceLog.Trace("Recruit.RecruitOne uid={0} get sp baodi rewardId={1} ",
|
|
player.UserID, rewardId);
|
|
}
|
|
else
|
|
{
|
|
//抽卡后的处理
|
|
maxQualityIndex = Math.Max(maxQualityIndex, maxQualityVal - 1);
|
|
TraceLog.Trace("Recruit.RecruitOne uid={0} get rewardId={1} quality={2}",
|
|
player.UserID, rewardId, maxQualityIndex + 1);
|
|
|
|
RecruitProcess(player, ref data, desc, maxQualityIndex);
|
|
}
|
|
TaskEXEvent.TriggerGemDrawN(player, 1);
|
|
return CSErrCode.None;
|
|
}
|
|
|
|
|
|
//获取抽卡奖励
|
|
private static string GetRecruitRewardId(PlayerOnGame player, ref RecruitData recruitData, GachaDesc desc,
|
|
out int maxQualityIndex)
|
|
{
|
|
maxQualityIndex = 0;
|
|
var rewardId = desc.reward;
|
|
var qualities = desc.guaranteedQuality;
|
|
for (var i = 0; i < recruitData.Record.Count; i++)
|
|
{
|
|
var quality = i + 1;
|
|
var times = recruitData.Record[i]; //已抽卡次数
|
|
var limitTimes = 0;
|
|
var jd = -1;
|
|
for (var j = 0; j < qualities.Length; j++)
|
|
{
|
|
if ((int)qualities[j] == quality)
|
|
{
|
|
jd = j;
|
|
limitTimes = desc.guaranteedTimes[j]; //保底次数
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (limitTimes == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (times >= (limitTimes - 1) && jd > -1)
|
|
{
|
|
rewardId = desc.guaranteedReward[jd];
|
|
maxQualityIndex = i;
|
|
TraceLog.Debug(
|
|
"Recruit.GetRecruitRewardId uid={0}, recruit trigger replace rewardId={1} quality={2}",
|
|
player.UserID, rewardId, quality);
|
|
}
|
|
}
|
|
|
|
return rewardId;
|
|
}
|
|
|
|
//发送奖励
|
|
private static void SendRecruitReward(PlayerOnGame player, UnifyOp unifyOp, string rewardId,
|
|
out int maxQualityVal, List<TypeIDValueString> result)
|
|
{
|
|
maxQualityVal = 0;
|
|
var rewards = RewardSvc.Reward(player, rewardId, false);
|
|
|
|
foreach (var reward in rewards)
|
|
{
|
|
var quality = (int)GetDescQuality((GoodsType)reward.type, reward.code);
|
|
if (quality == 0)
|
|
{
|
|
TraceLog.Error("Recruit.SendRecruitReward uid={0}, reward quality=0, type={1}, code={2}",
|
|
player.UserID, reward.type, reward.code);
|
|
continue;
|
|
}
|
|
|
|
maxQualityVal = Math.Max(maxQualityVal, quality);
|
|
unifyOp.AddGoods(reward.type, reward.code, reward.amount);
|
|
result.Add(new TypeIDValueString()
|
|
{ Type = reward.type, Id = new FixedStructString64(reward.code), Value = (int)reward.amount });
|
|
}
|
|
|
|
TraceLog.Debug("Recruit.SendRecruitReward uid={0}, get reward recruit max quality={1}", player.UserID,
|
|
maxQualityVal);
|
|
}
|
|
|
|
//抽卡后处理
|
|
private static void RecruitProcess(PlayerOnGame player, ref RecruitData recruitData, GachaDesc desc,
|
|
int maxQualityIndex)
|
|
{
|
|
for (var i = 0; i < recruitData.Record.Count; i++)
|
|
{
|
|
var quality = (CommonQuality)(i + 1);
|
|
if (i > maxQualityIndex)
|
|
{
|
|
if (desc.guaranteedQuality.Contains(quality))
|
|
{
|
|
recruitData.Record[i]++;
|
|
TraceLog.Debug("Recruit.RecruitProcess uid={0},add recruit num. quality={1},recruit num={2}",
|
|
player.UserID, (int)quality, recruitData.Record[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
recruitData.Record[i] = 0; //把当前替换的品质都置为0
|
|
TraceLog.Debug("Recruit.RecruitProcess uid={0},reset quality={1}", player.UserID, (int)quality);
|
|
}
|
|
}
|
|
|
|
string info = "";
|
|
for (int i = 0; i < recruitData.Record.Count; i++)
|
|
{
|
|
var num = recruitData.Record[i];
|
|
info += "quality=" + (i + 1) + ",num=" + num + "|";
|
|
}
|
|
|
|
TraceLog.Debug("Recruit.RecruitProcess uid={0},recruit record info|={1}", player.UserID, info);
|
|
}
|
|
|
|
//获取品质
|
|
private static CommonQuality GetDescQuality(GoodsType type, string cfgId)
|
|
{
|
|
switch (type)
|
|
{
|
|
case GoodsType.Items:
|
|
return ItemDescMgr.Instance.GetConfig(cfgId)?.quality ?? CommonQuality.None;
|
|
case GoodsType.Equipment:
|
|
return EquipDescMgr.Instance.GetConfig(cfgId)?.quality ?? CommonQuality.None;
|
|
case GoodsType.Gem:
|
|
return GemDescMgr.Instance.GetConfig(cfgId)?.quality ?? CommonQuality.None;
|
|
case GoodsType.EquipSkin:
|
|
return RoleModelDescMgr.Instance.GetConfig(int.Parse(cfgId))?.quality ?? CommonQuality.None;
|
|
case GoodsType.Wing:
|
|
return CommonQuality.DarkGold; //
|
|
case GoodsType.Exp:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return CommonQuality.None;
|
|
}
|
|
|
|
|
|
//抽卡消耗
|
|
public static CSErrCode RecruitCost(PlayerOnGame player, int poolId, int recruitCount, bool free,
|
|
ref IDStringValue cost)
|
|
{
|
|
ref var recruitData = ref player.RoleData.RecruitData;
|
|
var index = -1;
|
|
for (var i = 0; i < recruitData.Count; i++)
|
|
{
|
|
if (recruitData[i].PoolId == poolId)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 0)
|
|
{
|
|
return CSErrCode.Fail;
|
|
}
|
|
|
|
ref var data = ref recruitData[index];
|
|
var now = GameServerUtils.GetTimeSecond();
|
|
if (free && !AppTime.IsSameDay(data.LastFreeTime, now))
|
|
{
|
|
data.LastFreeTime = now; //免费
|
|
data.NextFreeTime = AppTime.GetTodayStartTime(GameServerUtils.GetTimeSecond()) + AppTime.SECONDS_ADAY +
|
|
1;
|
|
return CSErrCode.None;
|
|
}
|
|
|
|
var desc = GachaDescMgr.Instance.GetConfigByInternal(poolId);
|
|
var itemId = desc.costItemId;
|
|
var unifyOp = new UnifyOp(player, BillChangeItemReason.Recruit);
|
|
var itemCount = unifyOp.GetItemCount((int)GoodsType.Items, itemId);
|
|
var canRecruitCount = (int)(itemCount / Math.Max(1, desc.costItemValue)); //能抽几次
|
|
if (canRecruitCount < recruitCount)
|
|
{
|
|
recruitCount -= canRecruitCount;
|
|
unifyOp.CostItem(itemId, desc.costItemValue * canRecruitCount);
|
|
//钻石替换
|
|
unifyOp.CostDiamond(desc.costDiamondValue * recruitCount);
|
|
cost.Id.SetString(ItemId.Diamond);
|
|
cost.Value = desc.costItemValue * recruitCount;
|
|
var ret = unifyOp.CheckOp();
|
|
if (ret != CSErrCode.None)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unifyOp.CostItem(itemId, desc.costItemValue * recruitCount);
|
|
cost.Id.SetString(itemId);
|
|
cost.Value = desc.costItemValue * recruitCount;
|
|
var ret = unifyOp.CheckOp();
|
|
if (ret != CSErrCode.None)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return unifyOp.DoOp();
|
|
}
|
|
|
|
public static void SyncData(PlayerOnGame player)
|
|
{
|
|
var sync = new RecruitInfoSync();
|
|
sync.RecruitData.CopyFrom(ref player.RoleData.RecruitData);
|
|
player.SendToClient((int)CSGameMsgID.RecruitInfoSync, ref sync);
|
|
}
|
|
}
|
|
}
|