using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using PhoenixLib.Events; using WingsAPI.Game.Extensions.ItemExtension.Inventory; using WingsAPI.Game.Extensions.MinilandExtensions; using WingsAPI.Packets.Enums.Shells; using WingsEmu.Game; using WingsEmu.Game._i18n; using WingsEmu.Game.Characters.Events; using WingsEmu.Game.Configurations.Miniland; using WingsEmu.Game.Extensions; using WingsEmu.Game.Items; using WingsEmu.Game.Miniland; using WingsEmu.Game.Miniland.Events; using WingsEmu.Game.Networking; namespace WingsEmu.Plugins.BasicImplementations.Event.Miniland; public class MinigameRewardEventHandler : IAsyncEventProcessor { private readonly IGameItemInstanceFactory _gameItemInstanceFactory; private readonly IGameLanguageService _languageService; private readonly MinigameConfiguration _minigameConfiguration; private readonly IMinigameManager _minigameManager; private readonly IRandomGenerator _randomGenerator; private readonly MinigameInteraction ThisAction = MinigameInteraction.GetReward; public MinigameRewardEventHandler(IMinigameManager minigameManager, IRandomGenerator randomGenerator, MinigameConfiguration minigameConfiguration, IGameLanguageService languageService, IGameItemInstanceFactory gameItemInstanceFactory) { _minigameManager = minigameManager; _randomGenerator = randomGenerator; _minigameConfiguration = minigameConfiguration; _languageService = languageService; _gameItemInstanceFactory = gameItemInstanceFactory; } public async Task HandleAsync(MinigameRewardEvent e, CancellationToken cancellation) { MinilandInteractionInformationHolder possibleOldScore = _minigameManager.GetLastInteraction(e.Sender); if (possibleOldScore.Interaction != MinigameInteraction.DeclarateScore && possibleOldScore.MapObject != e.MapObject) { _minigameManager.ReportInteractionIncoherence(e.Sender, possibleOldScore.Interaction, possibleOldScore.MapObject, ThisAction, e.MapObject); return; } if (possibleOldScore.MapObject != e.MapObject || possibleOldScore.SavedRewards == default) { return; } if ((int)e.RewardLevel > (int)possibleOldScore.SavedRewards.maxRewardLevel) { await e.Sender.NotifyStrangeBehavior(StrangeBehaviorSeverity.ABUSING, "Incoherence in the rewards offered and the reward reclaimed."); e.Sender.SendMinigameRewardLevel(possibleOldScore.SavedRewards.maxRewardLevel); return; } MinigameRewards rewardsToGive = possibleOldScore.SavedRewards.rewards.FirstOrDefault(x => x.RewardLevel == e.RewardLevel); if (rewardsToGive == default || rewardsToGive.Rewards.Count < 1) { e.Sender.SendInfo(_languageService.GetLanguage(GameDialogKey.MINIGAME_INFO_NO_REWARD, e.Sender.UserLanguage)); e.Sender.SendMinigameReward(0, 0); return; } if (e.Coupon && !e.Sender.PlayerEntity.HasItem(_minigameConfiguration.Configuration.DoubleRewardCouponVnum)) { e.Sender.SendInfo(_languageService.GetLanguage(GameDialogKey.MINILAND_INFO_NO_ENOUGH_REWARD_COUPON, e.Sender.UserLanguage)); await e.Sender.NotifyStrangeBehavior(StrangeBehaviorSeverity.NORMAL, "Tried to do coupon reward without coupon."); return; } if (e.MapObject.InventoryItem.ItemInstance.DurabilityPoint < rewardsToGive.DurabilityCost) { e.Sender.SendInfo(_languageService.GetLanguage(GameDialogKey.MINILAND_INFO_NOT_ENOUGH_DURABILITY_POINT, e.Sender.UserLanguage)); return; } if (e.Sender.PlayerEntity.MinilandPoint < _minigameConfiguration.Configuration.MinigamePointsCostPerMinigame) { e.Sender.SendInfo(_languageService.GetLanguage(GameDialogKey.MINILAND_INFO_NOT_ENOUGH_PRODUCTION_POINTS, e.Sender.UserLanguage)); return; } e.MapObject.InventoryItem.ItemInstance.DurabilityPoint -= rewardsToGive.DurabilityCost; int toRemove = _minigameConfiguration.Configuration.MinigamePointsCostPerMinigame - e.Sender.PlayerEntity.GetMaxArmorShellValue(ShellEffectType.ReducedProductionPointConsumed); e.Sender.RemoveMinigamePoints((short)toRemove, _minigameConfiguration); _minigameManager.RegisterInteraction(e.Sender, new MinilandInteractionInformationHolder(ThisAction, e.MapObject)); MinigameReward rewardToGive = rewardsToGive.Rewards[_randomGenerator.RandomNumber(0, rewardsToGive.Rewards.Count)]; short itemAmount = (short)Math.Round(rewardToGive.Amount * (1 + e.Sender.PlayerEntity.GetMaxArmorShellValue(ShellEffectType.IncreasedProductionPossibility) * 0.01)); if (e.Coupon) { await e.Sender.RemoveItemFromInventory(_minigameConfiguration.Configuration.DoubleRewardCouponVnum); //This is because amount > 1 in things like weapons doesn't work. await GiveReward(e.Sender, rewardToGive.Vnum, itemAmount); } await GiveReward(e.Sender, rewardToGive.Vnum, itemAmount); e.Sender.SendMinigameReward(rewardToGive.Vnum, e.Coupon ? itemAmount * 2 : itemAmount); Minigame minigameConfiguration = _minigameManager.GetSpecificMinigameConfiguration(e.MapObject.InventoryItem.ItemInstance.ItemVNum); await e.Sender.EmitEventAsync(new MinigameRewardClaimedEvent { OwnerId = e.MapObject.CharacterId, MinigameVnum = e.MapObject.InventoryItem.ItemInstance.ItemVNum, MinigameType = minigameConfiguration.Type, RewardLevel = rewardsToGive.RewardLevel, Coupon = e.Coupon, ItemVnum = rewardToGive.Vnum, Amount = e.Coupon ? (short)(rewardToGive.Amount * 2) : (short)rewardToGive.Amount }); if (e.MapObject.CharacterId == e.Sender.PlayerEntity.Id) { return; } switch (e.RewardLevel) { case RewardLevel.FirstReward: e.MapObject.Level1BoxAmount++; break; case RewardLevel.SecondReward: e.MapObject.Level2BoxAmount++; break; case RewardLevel.ThirdReward: e.MapObject.Level3BoxAmount++; break; case RewardLevel.FourthReward: e.MapObject.Level4BoxAmount++; break; case RewardLevel.FifthReward: e.MapObject.Level5BoxAmount++; break; } //TODO Message notificating player did minigame. Should be configurable individuallly (per player) } private async Task GiveReward(IClientSession session, int vnum, short amount) { GameItemInstance item = _gameItemInstanceFactory.CreateItem(vnum, amount); await session.AddNewItemToInventory(item, sendGiftIsFull: true); } }