Skip to content

Commit

Permalink
Add draconic essence drops (#1107)
Browse files Browse the repository at this point in the history
Add drops of draconic essences to hard / very hard main story quests.

The visual indicator of the number of essence available is driven by
`quest_list[].daily_play_count`, which we already handle correctly in
`QuestService.ProcessQuestCompletion`. So the only change that needs to
be made is checking whether the quest drops essence, and whether our
play count is low enough, and then granting it.
  • Loading branch information
SapiensAnatis authored Oct 9, 2024
1 parent dab595f commit 1422698
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 77 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,38 @@ await this.Client.PostMsgpack<DungeonSkipStartResponse>(
);
}

[Fact]
public async Task DungeonSkipStart_RewardsCorrectDragonEssences()
{
// Ch. 5 / 4-3 Dark Terminus (Hard)
int questId = 100050209;
int existingEssenceQuantity = this
.ApiContext.PlayerMaterials.First(x => x.MaterialId == Materials.ChthoniussEssence)
.Quantity;

await this.AddToDatabase(new DbQuest() { QuestId = questId, DailyPlayCount = 0 });

DungeonSkipStartResponse response = (
await this.Client.PostMsgpack<DungeonSkipStartResponse>(
$"{Endpoint}/start",
new DungeonSkipStartRequest()
{
PartyNo = 1,
PlayCount = 4,
SupportViewerId = 1000,
QuestId = questId,
}
)
).Data;

response.UpdateDataList.MaterialList.Should().NotBeNull();
response
.UpdateDataList.MaterialList.Should()
.Contain(x => x.MaterialId == Materials.ChthoniussEssence)
.Which.Quantity.Should()
.Be(existingEssenceQuantity + 3);
}

[Fact]
public async Task DungeonSkipStart_CompletesDailyMissions()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public record QuestRewardData(
int FirstClearSetEntityQuantity4,
EntityTypes FirstClearSetEntityType5,
int FirstClearSetEntityId5,
int FirstClearSetEntityQuantity5
int FirstClearSetEntityQuantity5,
Materials DropLimitBreakMaterialId
)
{
[IgnoreMember]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public async Task ProcessEnemyDrops_RewardsCorrectDrops()
{
QuestData = null!,
Party = null!,
EnemyList = new Dictionary<int, IEnumerable<AtgenEnemy>>()
EnemyList = new Dictionary<int, IList<AtgenEnemy>>()
{
{
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ public async Task GenerateIngameResultData_CallsExpectedMethods()
eventDrops
)
);
this.mockDungeonRewardService.Setup(x => x.ProcessDraconicEssenceDrops(session))
.ReturnsAsync([]);

this.mockQuestService.Setup(x => x.GetQuestStamina(lSurtrSoloId, StaminaType.Single))
.ReturnsAsync(40);
Expand Down
2 changes: 1 addition & 1 deletion DragaliaAPI/DragaliaAPI/Features/Dungeon/DungeonSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class DungeonSession

public DateTimeOffset StartTime { get; init; }

public Dictionary<int, IEnumerable<AtgenEnemy>> EnemyList { get; set; } = new();
public Dictionary<int, IList<AtgenEnemy>> EnemyList { get; set; } = new();

public int PlayCount { get; init; } = 1;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace DragaliaAPI.Features.Dungeon;

public interface IQuestEnemyService
{
IEnumerable<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum);
IList<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum);

IEnumerable<AtgenEnemy> BuildQuestWallEnemyList(int wallId, int wallLevel);
IList<AtgenEnemy> BuildQuestWallEnemyList(int wallId, int wallLevel);
}
6 changes: 3 additions & 3 deletions DragaliaAPI/DragaliaAPI/Features/Dungeon/QuestEnemyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public QuestEnemyService(ILogger<QuestEnemyService> logger)
this.logger = logger;
}

public IEnumerable<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum)
public IList<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum)
{
AtgenEnemy[] enemyList = this.GetEnemyList(questId, areaNum);

Expand All @@ -34,7 +34,7 @@ public IEnumerable<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum)
return enemyList;
}

int areaCount = MasterAsset.QuestData[questId].AreaInfo.Count();
int areaCount = MasterAsset.QuestData[questId].AreaInfo.Count;
int totalQuantity = (int)Math.Round(questDropInfo.Drops.Sum(x => x.Quantity) / areaCount);

int totalRupies = AddVariance(questDropInfo.Rupies) / areaCount;
Expand Down Expand Up @@ -105,7 +105,7 @@ public IEnumerable<AtgenEnemy> BuildQuestEnemyList(int questId, int areaNum)
}

// Mercurial Gauntlet
public IEnumerable<AtgenEnemy> BuildQuestWallEnemyList(int wallId, int wallLevel)
public IList<AtgenEnemy> BuildQuestWallEnemyList(int wallId, int wallLevel)
{
List<AtgenEnemy> enemyList = GetWallEnemyList(wallId, wallLevel).ToList();
// should handle enemy drops but eh
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DragaliaAPI.Database.Entities;
using System.Collections;
using DragaliaAPI.Database.Entities;
using DragaliaAPI.Database.Repositories;
using DragaliaAPI.Features.Event;
using DragaliaAPI.Features.Missions;
Expand All @@ -7,6 +8,9 @@
using DragaliaAPI.Models.Generated;
using DragaliaAPI.Shared.Definitions.Enums;
using DragaliaAPI.Shared.Features.Presents;
using DragaliaAPI.Shared.MasterAsset;
using DragaliaAPI.Shared.MasterAsset.Models;
using DragaliaAPI.Shared.MasterAsset.Models.QuestRewards;

namespace DragaliaAPI.Features.Dungeon.Record;

Expand Down Expand Up @@ -64,17 +68,9 @@ int CoinDrop
int coinDrop = 0;
List<Entity> entities = new();

foreach (
AtgenTreasureRecord record in playRecord.TreasureRecord
?? Enumerable.Empty<AtgenTreasureRecord>()
)
foreach (AtgenTreasureRecord record in playRecord.TreasureRecord ?? [])
{
if (
!session.EnemyList.TryGetValue(
record.AreaIdx,
out IEnumerable<AtgenEnemy>? enemyList
)
)
if (!session.EnemyList.TryGetValue(record.AreaIdx, out IList<AtgenEnemy>? enemyList))
{
logger.LogWarning(
"Could not retrieve enemy list for area_idx {idx}",
Expand All @@ -84,7 +80,7 @@ out IEnumerable<AtgenEnemy>? enemyList
}

// Sometimes record.enemy is null for boss stages. Give all drops in this case.
IEnumerable<int> enemyRecord = record.Enemy ?? Enumerable.Repeat(1, enemyList.Count());
IEnumerable<int> enemyRecord = record.Enemy ?? Enumerable.Repeat(1, enemyList.Count);

foreach (
EnemyDropList enemyDropList in enemyList
Expand Down Expand Up @@ -112,6 +108,50 @@ EnemyDropList enemyDropList in enemyList
return (drops, manaDrop, coinDrop);
}

public async Task<IList<AtgenDropAll>> ProcessDraconicEssenceDrops(DungeonSession session)
{
if (
!MasterAsset.QuestRewardData.TryGetValue(
session.QuestId,
out QuestRewardData? questRewardData
)
|| questRewardData.DropLimitBreakMaterialId == 0
)
{
return [];
}

DbQuest dbRow = await questRepository.GetQuestDataAsync(session.QuestId);

// We are in this method after the play count has been incremented for the current completion
// It would be easier to run before, but the play count incrementing function also handles daily resets
int previousPlayCount = dbRow.DailyPlayCount - session.PlayCount;
int availableEssences = 3 - previousPlayCount;

if (availableEssences <= 0)
{
return [];
}

int rewardQuantity = Math.Min(session.PlayCount, availableEssences);

Entity essence =
new(
EntityTypes.Material,
(int)questRewardData.DropLimitBreakMaterialId,
rewardQuantity
);

RewardGrantResult result = await rewardService.GrantReward(essence);

if (result is not RewardGrantResult.Added)
{
presentService.AddPresent(new Present.Present(PresentMessage.QuestDailyBonus, essence));
}

return [essence.ToDropAll()];
}

public async Task<EventRewardData> ProcessEventRewards(
PlayRecord playRecord,
DungeonSession session
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,16 @@ await this.ProcessExperience(
ingameResultData.RewardRecord.MissionsClearSet = missionStatus.MissionsClearSet;
ingameResultData.RewardRecord.MissionComplete = missionStatus.MissionCompleteSet;

IList<AtgenDropAll> essenceDrops =
await dungeonRecordRewardService.ProcessDraconicEssenceDrops(session);

(IEnumerable<AtgenDropAll> dropList, int manaDrop, int coinDrop) =
await dungeonRecordRewardService.ProcessEnemyDrops(playRecord, session);

ingameResultData.RewardRecord.TakeCoin = coinDrop;
ingameResultData.GrowRecord.TakeMana = manaDrop;
ingameResultData.RewardRecord.DropAll.AddRange(dropList);
ingameResultData.RewardRecord.DropAll.AddRange(essenceDrops);

(
IEnumerable<AtgenScoreMissionSuccessList> scoreMissionSuccessList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ DungeonSession session
);

AtgenFirstMeeting ProcessFirstMeetingRewards(IList<long> connectingViewerIdList);
Task<IList<AtgenDropAll>> ProcessDraconicEssenceDrops(DungeonSession session);
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ IEnumerable<PartySettingList> party
PlayCount = playCount,
};

Dictionary<int, IEnumerable<AtgenEnemy>> enemyList = new(questData.AreaInfo.Count);
Dictionary<int, IList<AtgenEnemy>> enemyList = new(questData.AreaInfo.Count);

for (int areaIndex = 0; areaIndex < questData.AreaInfo.Count; areaIndex++)
{
Expand Down
11 changes: 11 additions & 0 deletions DragaliaAPI/DragaliaAPI/Features/Present/Present.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DragaliaAPI.Database.Entities;
using DragaliaAPI.Features.Reward;
using DragaliaAPI.Models.Generated;
using DragaliaAPI.Shared.Definitions.Enums;
using DragaliaAPI.Shared.Features.Presents;
Expand All @@ -23,6 +24,16 @@ public record Present(
int EntityLimitBreakCount = 0
)
{
public Present(PresentMessage messageId, Entity entity)
: this(
messageId,
entity.Type,
entity.Id,
entity.Quantity,
entity.BuildupCount ?? 0,
entity.LimitBreakCount ?? 0
) { }

public DateTimeOffset CreateTime { get; } = DateTimeOffset.UtcNow;

public TimeSpan? ExpiryTime { get; init; }
Expand Down
5 changes: 1 addition & 4 deletions DragaliaAPI/DragaliaAPI/Models/Generated/Components.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9473,17 +9473,14 @@ public partial class OddsInfo
[Key("drop_obj")]
public IEnumerable<AtgenDropObj> DropObj { get; set; } = [];

[Key("enemy")]
public IEnumerable<AtgenEnemy> Enemy { get; set; } = [];

[Key("grade")]
public IEnumerable<AtgenGrade> Grade { get; set; } = [];

public OddsInfo(
int areaIndex,
int reactionObjCount,
IEnumerable<AtgenDropObj> dropObj,
IEnumerable<AtgenEnemy> enemy,
IList<AtgenEnemy> enemy,
IEnumerable<AtgenGrade> grade
)
{
Expand Down
9 changes: 9 additions & 0 deletions DragaliaAPI/DragaliaAPI/Models/Generated/OddsInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MessagePack;

namespace DragaliaAPI.Models.Generated;

public partial class OddsInfo
{
[Key("enemy")]
public IList<AtgenEnemy> Enemy { get; set; } = [];
}

0 comments on commit 1422698

Please sign in to comment.