framework for handling stage lootbox drop

This commit is contained in:
rfi 2023-12-06 21:20:00 +07:00
parent f3468a908a
commit d6511d1088
4 changed files with 251 additions and 3 deletions

View File

@ -2468,7 +2468,7 @@ namespace AscNet.Common.MsgPack
public dynamic? ClientAssistInfo { get; set; } public dynamic? ClientAssistInfo { get; set; }
public List<dynamic> FlopRewardList { get; set; } = new(); public List<dynamic> FlopRewardList { get; set; } = new();
public dynamic? ArenaResult { get; set; } public dynamic? ArenaResult { get; set; }
public List<Object[]> MultiRewardGoodsList { get; set; } = new(); public List<List<RewardGoods>> MultiRewardGoodsList { get; set; } = new();
public Int32 ChallengeCount { get; set; } public Int32 ChallengeCount { get; set; }
public dynamic? UnionKillResult { get; set; } public dynamic? UnionKillResult { get; set; }
public dynamic? InfestorBossFightResult { get; set; } public dynamic? InfestorBossFightResult { get; set; }

View File

@ -44,6 +44,11 @@ namespace AscNet.Common
}; };
} }
public static bool IsHidden(this ItemTable item)
{
return item.ItemType == (int)ItemType.UnShow;
}
public struct EquipUpgradeInfo public struct EquipUpgradeInfo
{ {
public int Cost { get; init; } public int Cost { get; init; }
@ -57,7 +62,7 @@ namespace AscNet.Common
} }
} }
enum ItemType public enum ItemType
{ {
Assert = 1 << 0, Assert = 1 << 0,
Money = 1 << 1 | 1 << 0, Money = 1 << 1 | 1 << 0,

View File

@ -0,0 +1,219 @@
using AscNet.Common;
using AscNet.Common.MsgPack;
using AscNet.Common.Util;
using AscNet.Logging;
using AscNet.Table.V2.share.equip;
using AscNet.Table.V2.share.item;
using System.Reflection;
namespace AscNet.GameServer.Handlers.Drops
{
internal static class DropsHandler
{
#region Items
public const int ProofofHonor = 37;
public const int StrangeMark = 100;
public const int HQShard = 300;
public const int ChallengeMedal = 350;
public const int MarkofFriendship = 400;
public const int NightmareMedal = 401;
public const int ChristmasVoucher = 1000;
public const int StarryHairclip = 1001;
public const int SnowballBomb = 1002;
public const int IceCreamVoucher = 1003;
public const int GoldenRetriever = 1004;
public const int RedPacket = 1005;
public const int ChristmasFroggie = 1006;
public const int PlushSheep = 1007;
public const int SudokuHell = 1008;
public const int LegendsoftheWild = 1009;
public const int PortableSewingKit = 1010;
public const int HometownSnowman = 1011;
public const int DragonRevelation = 1012;
public const int ArtCollection = 1013;
public const int OldGuitar = 1014;
public const int BitingShark = 1015;
public const int MiniLantern = 1020;
public const int MessageCard = 1021;
public const int VenusRose = 1022;
public const int VenusCoupon = 1023;
public const int AntiqueMirror = 1024;
public const int PortableDetector = 1025;
public const int SwordCommand = 1026;
public const int SignalPoint = 1027;
public const int RaceToken = 1028;
public const int EnameledPlumBlossom = 1029;
public const int NewYearToken = 1030;
public const int FateToken = 1031;
public const int CrystalHeartPlush = 1032;
public const int MoonDust = 1033;
public const int CrumpledPaper = 1034;
public const int KleinBottle = 1035;
public const int FiveStarWeaponDrop = 10004;
public const int FourStarWeaponDrop = 10005;
public const int ThreeStarWeaponDrop = 10006;
public const int TwoStarWeaponDrop = 10007;
public const int FiveStarMemoryDrop = 10009;
public const int FourStarMemoryDrop = 10010;
public const int ThreeStarMemoryDrop = 10011;
public const int TwoStarMemoryDrop = 10012;
public const int FiveStarEquipmentDrop = 10013;
public const int FourStarEquipmentDrop = 10014;
public const int ThreeStarEquipmentDrop = 10015;
public const int TwoStarEquipmentDrop = 10016;
public const int OneStarEquipmentDrop = 10017;
public const int TwoToFourStarEquipmentDrop = 10018;
public const int MajorOverclockmaterial = 10034;
public const int OverclockMaterialI = 10035;
public const int FiveStarHQFacility = 10036;
public const int FourStarHQFacility = 10037;
public const int ThreeStarHQFacility = 10038;
public const int ThreeToSixStarEquipmentDrop = 10039;
public const int ThreeToFiveStarEquipmentDrop = 10040;
public const int VoltaireSetDrop = 10041;
public const int GloriaSetDrop = 10042;
public const int RichelieuSetDrop = 10043;
public const int SamanthaSetDrop = 10044;
public const int IkeSetDrop = 10045;
public const int MozartSetDrop = 10046;
public const int Carrielynnsetdrop = 10047;
public const int AifeSetDrop = 10048;
public const int SixStarEquipmentDrop = 10049;
public const int SixStarWeaponDrop = 10050;
public const int SixStarMemoryDrop = 10051;
/*public const int MemoryEnhancer = 10052;
public const int MemoryEnhancer = 10053;
public const int MemoryEnhancer = 10054;
public const int MemoryEnhancer = 10055;
public const int MemoryEnhancer = 10056;*/
public const int BorderCertificate = 10057;
public const int ProcessingUnit = 10058;
public const int FalseWordsCertificate = 10059;
public const int HonorMedal = 10060;
public const int HeterosoilGrownCertificate = 10061;
public const int MemorialPhotoAlbum = 10062;
public const int CafeDecor = 11001;
public const int JapaneseDecor = 11002;
public const int CyberDecor = 11003;
public const int CafeBlueprint = 11004;
public const int JapaneseBlueprint = 11005;
public const int CyberBlueprint = 11006;
public const int Yan = 62301;
public const int Rang = 62302;
public const int Ying = 62303;
public const int Sui = 62304;
public const int Tu = 62305;
public const int Su = 62306;
public const int Nuan = 62307;
public const int Chun = 62308;
public const int YanRangYingSui = 62310;
public const int TuSuNuanChun = 62311;
public const int NewYearBox = 62312;
public const int SilverHammer = 62313;
public const int GoldenHammer = 62314;
public const int AwakenedLion = 62315;
public const int FortuneLion = 62316;
public const int LockCharm = 62317;
public const int FortuneCharacterBag = 62319;
public const int FOSInstructorMedal = 96001;
public const int Prayer = 96108;
#endregion
// 5★ Memory Drop
[DropHandler(FiveStarMemoryDrop)]
public static IEnumerable<DropHandlerRet> FiveStarMemoryDropHandler(Session session, int count)
{
List<DropHandlerRet> rets = new();
EquipTable[] memoryPool = TableReaderV2.Parse<EquipTable>().Where(x => x.Type == 0 && x.Quality == 5).ToArray();
if (GetProgressiveChance((int)session.player.PlayerData.Level, 5))
{
EquipTable equip = memoryPool[Random.Shared.Next(0, memoryPool.Length)];
rets.Add(new()
{
TemplateId = equip.Id,
Count = 1,
Level = 1,
Quality = equip.Quality
});
NotifyEquipDataList notifyEquipData = new();
notifyEquipData.EquipDataList.Add(session.character.AddEquip((uint)equip.Id));
session.SendPush(notifyEquipData);
}
return rets;
}
/// <summary>
/// Progressive chance of getting the item based on item quality and commandant level
/// </summary>
private static bool GetProgressiveChance(int level, int quality)
{
return true;
}
}
public static class DropsHandlerFactory
{
public static readonly Dictionary<int, DropHandlerDelegate> dropHandlers = new();
static readonly Logger log = new(typeof(DropsHandlerFactory), LogLevel.DEBUG, LogLevel.DEBUG);
static DropsHandlerFactory()
{
log.LogLevelColor[LogLevel.INFO] = ConsoleColor.White;
log.Info("Loading drop handlers...");
IEnumerable<Type> classes = from t in Assembly.GetExecutingAssembly().GetTypes()
select t;
foreach (var method in classes.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)))
{
var attr = method.GetCustomAttribute<DropHandler>(false);
if (attr is null)
continue;
foreach (var itemId in attr.ItemIds)
{
if (dropHandlers.ContainsKey(itemId))
continue;
dropHandlers.Add(itemId, (DropHandlerDelegate)Delegate.CreateDelegate(typeof(DropHandlerDelegate), method));
}
#if DEBUG
log.Info($"Loaded {method.Name}");
#endif
}
log.Info("Finished loading drop handlers");
}
public static DropHandlerDelegate? GetDropHandler(int itemId)
{
dropHandlers.TryGetValue(itemId, out DropHandlerDelegate? handler);
return handler;
}
}
public delegate IEnumerable<DropHandlerRet> DropHandlerDelegate(Session session, int count);
[AttributeUsage(AttributeTargets.Method)]
public class DropHandler : Attribute
{
public int[] ItemIds { get; }
public DropHandler(params int[] itemIds)
{
ItemIds = itemIds;
}
}
public struct DropHandlerRet
{
public int TemplateId;
public int Count;
public int Level;
public int Quality;
}
}

View File

@ -1,9 +1,12 @@
using AscNet.Common.Database; using AscNet.Common.Database;
using AscNet.Common.MsgPack; using AscNet.Common.MsgPack;
using AscNet.Common.Util; using AscNet.Common.Util;
using AscNet.Common;
using AscNet.Table.share.fuben; using AscNet.Table.share.fuben;
using AscNet.Table.V2.share.item;
using AscNet.Table.V2.share.reward; using AscNet.Table.V2.share.reward;
using MessagePack; using MessagePack;
using AscNet.GameServer.Handlers.Drops;
namespace AscNet.GameServer.Handlers namespace AscNet.GameServer.Handlers
{ {
@ -240,7 +243,7 @@ namespace AscNet.GameServer.Handlers
if (rewardGood is not null) if (rewardGood is not null)
{ {
// Item type formula // Item type formula
int rewardTypeVal = Math.Max((int)MathF.Floor((rewardGood.TemplateId > 0 ? rewardGood.TemplateId : rewardGood.Id) / 1000000), 1); int rewardTypeVal = (int)MathF.Floor((rewardGood.TemplateId > 0 ? rewardGood.TemplateId : rewardGood.Id) / 1000000) + 1;
RewardType rewardType = RewardType.Item; RewardType rewardType = RewardType.Item;
try try
{ {
@ -254,6 +257,26 @@ namespace AscNet.GameServer.Handlers
// TODO: Implement other types. Other types are behaving weirdly // TODO: Implement other types. Other types are behaving weirdly
if (rewardType == RewardType.Item) if (rewardType == RewardType.Item)
{ {
ItemTable? itemData = TableReaderV2.Parse<ItemTable>().Find(x => x.Id == rewardGood.TemplateId);
if (itemData is not null)
{
// Custom handler for some items that aren't meant to be in the inventory.
DropHandlerDelegate? dropHandler = DropsHandlerFactory.GetDropHandler(itemData.Id);
if (itemData.IsHidden() && dropHandler is not null)
{
rewards.AddRange(dropHandler.Invoke(session, rewardGood.Count).Select(x => new RewardGoods()
{
Id = rewardGood.Id,
TemplateId = x.TemplateId,
Count = x.Count,
Level = x.Level,
RewardType = (int)MathF.Floor(x.TemplateId / 1000000) + 1,
Quality = x.Quality
}));
continue;
}
}
notifyItemData.ItemDataList.Add(session.inventory.Do(rewardGood.TemplateId, rewardGood.Count)); notifyItemData.ItemDataList.Add(session.inventory.Do(rewardGood.TemplateId, rewardGood.Count));
rewards.Add(new() rewards.Add(new()
@ -315,6 +338,7 @@ namespace AscNet.GameServer.Handlers
StageId = (uint)stageData.StageId, StageId = (uint)stageData.StageId,
StarsMark = (int)stageData.StarsMark, StarsMark = (int)stageData.StarsMark,
RewardGoodsList = rewards, RewardGoodsList = rewards,
MultiRewardGoodsList = { rewards },
NpcHpInfo = req.Result.NpcHpInfo, NpcHpInfo = req.Result.NpcHpInfo,
ChallengeCount = req.Result.RebootCount ChallengeCount = req.Result.RebootCount
} }