323 lines
No EOL
17 KiB
C#
323 lines
No EOL
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using PhoenixLib.Events;
|
|
using WingsAPI.Game.Extensions.ItemExtension.Inventory;
|
|
using WingsAPI.Game.Extensions.Quests;
|
|
using WingsAPI.Game.Extensions.Quicklist;
|
|
using WingsEmu.DTOs.Quests;
|
|
using WingsEmu.DTOs.Skills;
|
|
using WingsEmu.Game;
|
|
using WingsEmu.Game._enum;
|
|
using WingsEmu.Game._i18n;
|
|
using WingsEmu.Game.Algorithm;
|
|
using WingsEmu.Game.Battle;
|
|
using WingsEmu.Game.Buffs;
|
|
using WingsEmu.Game.Characters.Events;
|
|
using WingsEmu.Game.Configurations;
|
|
using WingsEmu.Game.Extensions;
|
|
using WingsEmu.Game.Items;
|
|
using WingsEmu.Game.Managers;
|
|
using WingsEmu.Game.Managers.StaticData;
|
|
using WingsEmu.Game.Networking;
|
|
using WingsEmu.Game.Quests;
|
|
using WingsEmu.Game.Quests.Configurations;
|
|
using WingsEmu.Game.Quests.Event;
|
|
using WingsEmu.Game.Skills;
|
|
using WingsEmu.Packets.Enums;
|
|
using WingsEmu.Packets.Enums.Character;
|
|
|
|
namespace Plugin.QuestImpl.Handlers
|
|
{
|
|
public class QuestRewardEventHandler : IAsyncEventProcessor<QuestRewardEvent>
|
|
{
|
|
private static readonly HashSet<int> SkillsToLearn = new()
|
|
{
|
|
(int)SkillsVnums.BEGINNER_PHYSICAL_STRENGTH, (int)SkillsVnums.BEGINNER_SPEED,
|
|
(int)SkillsVnums.BEGINNER_INTELLIGENCE, (int)SkillsVnums.BEGINNER_HP_RECOVERY
|
|
};
|
|
|
|
private static readonly HashSet<int> TarotRewards = new()
|
|
{
|
|
(int)ItemVnums.TAROT_FOOL, (int)ItemVnums.TAROT_MAGICIAN, (int)ItemVnums.TAROT_LOVERS, (int)ItemVnums.TAROT_HERMIT, (int)ItemVnums.TAROT_DEATH,
|
|
(int)ItemVnums.TAROT_DEVIL, (int)ItemVnums.TAROT_TOWER, (int)ItemVnums.TAROT_STAR, (int)ItemVnums.TAROT_MOON, (int)ItemVnums.TAROT_SUN
|
|
};
|
|
|
|
private readonly IBuffFactory _buffFactory;
|
|
private readonly ICharacterAlgorithm _characterAlgorithm;
|
|
private readonly IDropRarityConfigurationProvider _dropRarityConfigurationProvider;
|
|
private readonly IGameItemInstanceFactory _gameItemInstanceFactory;
|
|
private readonly IGameLanguageService _gameLanguageService;
|
|
private readonly GameMinMaxConfiguration _gameMinMaxConfiguration;
|
|
private readonly IItemsManager _itemsManager;
|
|
private readonly IQuestManager _questManager;
|
|
private readonly QuestsRatesConfiguration _questsRates;
|
|
private readonly IRandomGenerator _randomGenerator;
|
|
private readonly IRankingManager _rankingManager;
|
|
private readonly IReputationConfiguration _reputationConfiguration;
|
|
private readonly ISkillsManager _skillsManager;
|
|
private readonly SoundFlowerConfiguration _soundFlowerConfiguration;
|
|
|
|
public QuestRewardEventHandler(IGameItemInstanceFactory gameItemInstanceFactory, ICharacterAlgorithm characterAlgorithm, IRandomGenerator randomGenerator, ISkillsManager skillsManager,
|
|
IItemsManager itemsManager, QuestsRatesConfiguration questsRates, GameMinMaxConfiguration gameMinMaxConfiguration, IGameLanguageService gameLanguageService,
|
|
IDropRarityConfigurationProvider dropRarityConfigurationProvider, IQuestManager questManager, IReputationConfiguration reputationConfiguration, IRankingManager rankingManager,
|
|
SoundFlowerConfiguration soundFlowerConfiguration, IBuffFactory buffFactory)
|
|
{
|
|
_gameItemInstanceFactory = gameItemInstanceFactory;
|
|
_characterAlgorithm = characterAlgorithm;
|
|
_randomGenerator = randomGenerator;
|
|
_skillsManager = skillsManager;
|
|
_itemsManager = itemsManager;
|
|
_questsRates = questsRates;
|
|
_gameMinMaxConfiguration = gameMinMaxConfiguration;
|
|
_gameLanguageService = gameLanguageService;
|
|
_dropRarityConfigurationProvider = dropRarityConfigurationProvider;
|
|
_questManager = questManager;
|
|
_reputationConfiguration = reputationConfiguration;
|
|
_rankingManager = rankingManager;
|
|
_soundFlowerConfiguration = soundFlowerConfiguration;
|
|
_buffFactory = buffFactory;
|
|
}
|
|
|
|
public async Task HandleAsync(QuestRewardEvent e, CancellationToken cancellation)
|
|
{
|
|
IClientSession session = e.Sender;
|
|
|
|
CharacterQuest characterQuest = session.PlayerEntity.GetQuestById(e.QuestId);
|
|
if (characterQuest == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (characterQuest.Quest.Prizes.Any())
|
|
{
|
|
TutorialDto qPayScript = _questManager.GetQuestPayScriptByQuestId(characterQuest.QuestId);
|
|
if (!e.ClaimReward && qPayScript != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// We only really care about the random reward given to QuestRewardType.RandomReward
|
|
IReadOnlyCollection<CharacterQuestGeneratedReward> rndRewards = GiveRewards(session, characterQuest);
|
|
session.SendQrPacket(characterQuest, rndRewards, _questsRates);
|
|
if (qPayScript != null)
|
|
{
|
|
session.PlayerEntity.SaveScript(qPayScript.ScriptId, qPayScript.ScriptIndex, TutorialActionType.WAIT_FOR_REWARDS_CLAIM, DateTime.UtcNow);
|
|
}
|
|
}
|
|
|
|
if (characterQuest.Quest.QuestType != QuestType.NOTHING)
|
|
{
|
|
session.PlayerEntity.AddDignity(50, _gameMinMaxConfiguration, _gameLanguageService, _reputationConfiguration, _rankingManager.TopReputation);
|
|
}
|
|
|
|
if (_soundFlowerConfiguration.WildSoundFlowerQuestVnums.Contains(characterQuest.QuestId))
|
|
{
|
|
int rndBuffVnum = _soundFlowerConfiguration.PossibleBuffs.ElementAt(_randomGenerator.RandomNumber(_soundFlowerConfiguration.PossibleBuffs.Count));
|
|
|
|
Buff rndBuff = _buffFactory.CreateBuff(rndBuffVnum, session.PlayerEntity);
|
|
await session.PlayerEntity.AddBuffsAsync(new[] { rndBuff });
|
|
}
|
|
|
|
HandleSpecialQuestsRewards(session, characterQuest);
|
|
}
|
|
|
|
private IReadOnlyCollection<CharacterQuestGeneratedReward> GiveRewards(IClientSession session, CharacterQuest characterQuest)
|
|
{
|
|
IEnumerable<QuestPrizeDto> prizes = characterQuest.Quest.Prizes;
|
|
if (prizes == null)
|
|
{
|
|
return Array.Empty<CharacterQuestGeneratedReward>();
|
|
}
|
|
|
|
List<CharacterQuestGeneratedReward> generatedRewards = new();
|
|
foreach (QuestPrizeDto prize in prizes)
|
|
{
|
|
GameItemInstance itemToAdd;
|
|
switch (prize.RewardType)
|
|
{
|
|
case (byte)QuestRewardType.Gold:
|
|
session.EmitEventAsync(new GenerateGoldEvent(prize.Data0 * _questsRates.GoldRate, true));
|
|
break;
|
|
case (byte)QuestRewardType.SecondGold:
|
|
session.EmitEventAsync(new GenerateGoldEvent(prize.Data0 * _questsRates.BaseGold * _questsRates.GoldRate, true));
|
|
break;
|
|
case (byte)QuestRewardType.Exp:
|
|
session.EmitEventAsync(new AddExpEvent(_characterAlgorithm.GetLevelXpPercentage((short)prize.Data0, (short)prize.Data1) * _questsRates.XpRate, LevelType.Level));
|
|
break;
|
|
case (byte)QuestRewardType.SecondExp:
|
|
session.EmitEventAsync(new AddExpEvent(prize.Data0 * _questsRates.BaseXp * _questsRates.XpRate, LevelType.Level));
|
|
break;
|
|
case (byte)QuestRewardType.JobExp:
|
|
long exp = session.PlayerEntity.UseSp && session.PlayerEntity.Specialist != null
|
|
? _characterAlgorithm.GetSpecialistJobXpPercentage((short)prize.Data0, (short)prize.Data1, session.PlayerEntity.Specialist.IsFunSpecialist()) * _questsRates.JobXpRate
|
|
: _characterAlgorithm.GetJobXpPercentage((short)prize.Data0, (short)prize.Data1) * _questsRates.JobXpRate;
|
|
session.EmitEventAsync(new AddExpEvent(exp, session.PlayerEntity.UseSp && session.PlayerEntity.Specialist != null ? LevelType.SpJobLevel : LevelType.JobLevel));
|
|
break;
|
|
case (byte)QuestRewardType.RandomReward:
|
|
var possibleRewards = new[] { prize.Data0, prize.Data1, prize.Data2, prize.Data3 }.Where(s => s != -1).ToList();
|
|
int rndRewardVnum = possibleRewards[_randomGenerator.RandomNumber(possibleRewards.Count)];
|
|
|
|
itemToAdd = _gameItemInstanceFactory.CreateItem(rndRewardVnum, prize.Data4);
|
|
session.AddNewItemToInventory(itemToAdd, sendGiftIsFull: true);
|
|
generatedRewards.Add(new CharacterQuestGeneratedReward
|
|
{
|
|
ItemVnum = rndRewardVnum,
|
|
Amount = prize.Data4
|
|
});
|
|
break;
|
|
case (byte)QuestRewardType.AllRewards:
|
|
foreach (int itemVnum in new[] { prize.Data0, prize.Data1, prize.Data2, prize.Data3 })
|
|
{
|
|
if (itemVnum == -1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
IGameItem item = _itemsManager.GetItem(itemVnum);
|
|
sbyte randomRarity = _dropRarityConfigurationProvider.GetRandomRarity(item.ItemType);
|
|
|
|
itemToAdd = _gameItemInstanceFactory.CreateItem(itemVnum, 1, 0, randomRarity);
|
|
session.AddNewItemToInventory(itemToAdd, sendGiftIsFull: true);
|
|
}
|
|
|
|
break;
|
|
case (byte)QuestRewardType.Reput:
|
|
session.EmitEventAsync(new GenerateReputationEvent { Amount = prize.Data0 * _questsRates.ReputRate, SendMessage = true });
|
|
break;
|
|
case (byte)QuestRewardType.ThirdGold:
|
|
session.EmitEventAsync(new GenerateGoldEvent(prize.Data0 * characterQuest.ObjectiveAmount.Sum(s => s.Value.RequiredAmount) * session.PlayerEntity.Level * _questsRates.GoldRate,
|
|
true));
|
|
break;
|
|
case (byte)QuestRewardType.ThirdExp:
|
|
session.EmitEventAsync(new AddExpEvent(prize.Data0 * characterQuest.ObjectiveAmount.Sum(s => s.Value.RequiredAmount) * session.PlayerEntity.Level * _questsRates.XpRate,
|
|
LevelType.Level));
|
|
break;
|
|
case (byte)QuestRewardType.SecondJobExp:
|
|
session.EmitEventAsync(new AddExpEvent(prize.Data0 * characterQuest.ObjectiveAmount.Sum(s => s.Value.RequiredAmount) * session.PlayerEntity.Level * _questsRates.JobXpRate,
|
|
LevelType.JobLevel));
|
|
break;
|
|
case (byte)QuestRewardType.Unknow:
|
|
break;
|
|
case (byte)QuestRewardType.ItemsDependingOnClass:
|
|
GameItemInstance itemDependingOnClass;
|
|
IGameItem gameItem;
|
|
sbyte randomItemRarity;
|
|
|
|
switch (session.PlayerEntity.Class)
|
|
{
|
|
case ClassType.Swordman:
|
|
gameItem = _itemsManager.GetItem(prize.Data0);
|
|
if (gameItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
randomItemRarity = _dropRarityConfigurationProvider.GetRandomRarity(gameItem.ItemType);
|
|
|
|
itemDependingOnClass = _gameItemInstanceFactory.CreateItem(prize.Data0, prize.Data4, 0, randomItemRarity);
|
|
break;
|
|
case ClassType.Archer:
|
|
gameItem = _itemsManager.GetItem(prize.Data1);
|
|
if (gameItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
randomItemRarity = _dropRarityConfigurationProvider.GetRandomRarity(gameItem.ItemType);
|
|
|
|
itemDependingOnClass = _gameItemInstanceFactory.CreateItem(prize.Data1, prize.Data4, 0, randomItemRarity);
|
|
break;
|
|
case ClassType.Magician:
|
|
gameItem = _itemsManager.GetItem(prize.Data2);
|
|
if (gameItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
randomItemRarity = _dropRarityConfigurationProvider.GetRandomRarity(gameItem.ItemType);
|
|
|
|
itemDependingOnClass = _gameItemInstanceFactory.CreateItem(prize.Data2, prize.Data4, 0, randomItemRarity);
|
|
break;
|
|
default:
|
|
gameItem = _itemsManager.GetItem(prize.Data3);
|
|
if (gameItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
randomItemRarity = _dropRarityConfigurationProvider.GetRandomRarity(gameItem.ItemType);
|
|
|
|
itemDependingOnClass = _gameItemInstanceFactory.CreateItem(prize.Data3, prize.Data4, 0, randomItemRarity);
|
|
break;
|
|
}
|
|
|
|
if (itemDependingOnClass == null)
|
|
{
|
|
return Array.Empty<CharacterQuestGeneratedReward>();
|
|
}
|
|
|
|
session.AddNewItemToInventory(itemDependingOnClass, sendGiftIsFull: true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return generatedRewards;
|
|
}
|
|
|
|
private void HandleSpecialQuestsRewards(IClientSession session, CharacterQuest characterQuest)
|
|
{
|
|
switch (characterQuest.QuestId)
|
|
{
|
|
case (short)QuestsVnums.SORAYA_LUNCH_TO_CALVIN:
|
|
GameItemInstance calvinLunch = _gameItemInstanceFactory.CreateItem((short)ItemVnums.DELICIOUS_LUNCH);
|
|
session.AddNewItemToInventory(calvinLunch, true, sendGiftIsFull: true);
|
|
break;
|
|
case (short)QuestsVnums.GIVE_MALCOM_ADVENTURER_SHOES:
|
|
GameItemInstance malcomShoes = _gameItemInstanceFactory.CreateItem((short)ItemVnums.ADVENTURER_SHOES, 1, 3);
|
|
malcomShoes.DarkResistance += (short)(malcomShoes.GameItem.DarkResistance * 3);
|
|
session.AddNewItemToInventory(malcomShoes, true, sendGiftIsFull: true);
|
|
break;
|
|
case (short)QuestsVnums.CALVIN_ADVENTURER_TRAINING_SKILLS:
|
|
foreach (SkillDTO ski in _skillsManager.GetSkills())
|
|
{
|
|
if (!SkillsToLearn.Contains(ski.Id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Find higher passive already in PlayerEntity
|
|
CharacterSkill findHigherPassive = session.PlayerEntity.CharacterSkills.Values.FirstOrDefault(x => x.Skill.IsPassiveSkill()
|
|
&& x.Skill.CastId == ski.CastId && x.Skill.Id > ski.Id);
|
|
|
|
if (findHigherPassive != null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var passive = new CharacterSkill { SkillVNum = ski.Id };
|
|
|
|
session.PlayerEntity.CharacterSkills[ski.Id] = passive;
|
|
session.PlayerEntity.Skills.Add(passive);
|
|
}
|
|
|
|
session.PlayerEntity.ClearSkillCooldowns();
|
|
session.RefreshPassiveBCards();
|
|
session.RefreshSkillList();
|
|
session.RefreshQuicklist();
|
|
break;
|
|
case (short)QuestsVnums.FORTUNE_TELLER_1:
|
|
case (short)QuestsVnums.FORTUNE_TELLER_2:
|
|
case (short)QuestsVnums.FORTUNE_TELLER_3:
|
|
case (short)QuestsVnums.FORTUNE_TELLER_4:
|
|
case (short)QuestsVnums.FORTUNE_TELLER_5:
|
|
int randomTarotVnum = TarotRewards.ElementAt(_randomGenerator.RandomNumber(TarotRewards.Count));
|
|
GameItemInstance randomTarot = _gameItemInstanceFactory.CreateItem((short)randomTarotVnum);
|
|
session.AddNewItemToInventory(randomTarot, true, sendGiftIsFull: true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |