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

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);
}
}
}