Skip to content

Commit 62271d2

Browse files
authored
Merge pull request #996 from pacampbell/filter_world_quests_by_area_rank
feat: Filter World Quests by party Leader Area Rank
2 parents eeb294e + 499c243 commit 62271d2

3 files changed

Lines changed: 85 additions & 5 deletions

File tree

Arrowgene.Ddon.GameServer/Handler/PartyPartyCreateHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public override S2CPartyPartyCreateRes Handle(GameClient client, C2SPartyPartyCr
2727
party.AddHost(client);
2828

2929
PlayerPartyMember join = party.Join(client);
30+
// Re-roll any world quests the leader can't take yet (base constructor rolls unfiltered).
31+
party.QuestState.EnforceInitialPoolEligibility();
3032

3133
var progress = Server.Database.GetQuestProgressByType(client.Character.CommonId, QuestType.All);
3234
foreach (var questProgress in progress)

Arrowgene.Ddon.GameServer/Handler/QuestGetSetQuestListHandler.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Arrowgene.Ddon.Shared.Model.Quest;
77
using Arrowgene.Logging;
88
using System.Collections.Generic;
9+
using System.Linq;
910

1011
namespace Arrowgene.Ddon.GameServer.Handler
1112
{
@@ -40,6 +41,8 @@ public override S2CQuestGetSetQuestListRes Handle(GameClient client, C2SQuestGet
4041
* are random fetch, deliver and kill type quests.
4142
*/
4243

44+
var leaderCharacter = client.Party.Leader?.Client.Character;
45+
4346
// Populate state for all quests currently in progress by the player
4447
foreach (var questScheduleId in client.Party.QuestState.GetActiveQuestScheduleIds())
4548
{
@@ -49,7 +52,7 @@ public override S2CQuestGetSetQuestListRes Handle(GameClient client, C2SQuestGet
4952
continue;
5053
}
5154

52-
CompletedQuest questStats = client.Party.Leader?.Client.Character.CompletedQuests.GetValueOrDefault(quest.QuestId);
55+
CompletedQuest questStats = leaderCharacter?.CompletedQuests.GetValueOrDefault(quest.QuestId);
5356
QuestState questState = client.Party.QuestState.GetQuestState(quest);
5457
res.SetQuestList.Add(quest.ToCDataSetQuestList(questState?.Step ?? 0, questStats?.ClearCount ?? 0));
5558
}
@@ -66,7 +69,15 @@ public override S2CQuestGetSetQuestListRes Handle(GameClient client, C2SQuestGet
6669
continue;
6770
}
6871

69-
CompletedQuest questStats = client.Party.Leader?.Client.Character.CompletedQuests.GetValueOrDefault(quest.QuestId);
72+
if (quest.OrderConditions.Any(c => c.Type == QuestOrderConditionType.AreaRank
73+
&& (leaderCharacter == null
74+
|| !leaderCharacter.AreaRanks.ContainsKey((QuestAreaId)c.Param01)
75+
|| Server.AreaRankManager.GetEffectiveRank(leaderCharacter, (QuestAreaId)c.Param01) < (uint)c.Param02)))
76+
{
77+
continue;
78+
}
79+
80+
CompletedQuest questStats = leaderCharacter?.CompletedQuests.GetValueOrDefault(quest.QuestId);
7081
res.SetQuestList.Add(quest.ToCDataSetQuestList(0, questStats?.ClearCount ?? 0));
7182
client.Party.QuestState.AddNewQuest(quest, 0);
7283
// Enemy requests arrive before the quest list, so loaded groups may have generic enemies. Reset them.

Arrowgene.Ddon.GameServer/Quests/QuestStateManager.cs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public abstract class QuestStateManager
177177
protected Dictionary<uint, QuestState> ActiveQuests { get; set; }
178178
private Dictionary<StageLayoutId, HashSet<uint>> QuestLookupTable { get; set; }
179179
private List<QuestId> CompletedWorldQuests { get; set; }
180-
private Dictionary<QuestAreaId, HashSet<uint>> RolledInstanceWorldQuests { get; set; }
180+
protected Dictionary<QuestAreaId, HashSet<uint>> RolledInstanceWorldQuests { get; set; }
181181

182182
// Deferred Generic Work to be triggered at various points
183183
public Dictionary<QuestProgressWorkType, List<QuestProgressWork>> ProgressWork { get; set; }
@@ -529,6 +529,24 @@ public HashSet<uint> AreaQuests(QuestAreaId areaId)
529529
}
530530
}
531531

532+
protected virtual uint GetEffectiveAreaRank(Character character, QuestAreaId areaId)
533+
{
534+
return character.AreaRanks.TryGetValue(areaId, out var rank) ? rank.Rank : 0;
535+
}
536+
537+
protected Quest RollEligibleQuestVariant(QuestId questId, Character leaderCharacter)
538+
{
539+
var candidates = QuestManager.GetQuestScheduleIdsForQuestId(questId)
540+
.Select(id => QuestManager.GetQuestByScheduleId(id))
541+
.Where(q => q != null && !q.OrderConditions.Any(c => c.Type == QuestOrderConditionType.AreaRank
542+
&& (leaderCharacter == null
543+
|| GetEffectiveAreaRank(leaderCharacter, (QuestAreaId)c.Param01) < (uint)c.Param02)))
544+
.ToList();
545+
546+
if (candidates.Count == 0) return null;
547+
return candidates[Random.Shared.Next(candidates.Count)];
548+
}
549+
532550
public QuestState GetQuestState(uint questScheduleId)
533551
{
534552
lock (ActiveQuests)
@@ -707,14 +725,24 @@ protected PacketQueue SendWalletRewards(DdonGameServer server, GameClient client
707725
return packets;
708726
}
709727

728+
public virtual void EnforceInitialPoolEligibility() { }
729+
730+
protected virtual Quest RollQuestVariant(QuestId questId)
731+
{
732+
return QuestManager.RollQuestForQuestId(questId);
733+
}
734+
710735
public void ResetInstance()
711736
{
712737
lock (ActiveQuests)
713738
{
714739
foreach (var questId in CompletedWorldQuests)
715740
{
716-
var quest = QuestManager.RollQuestForQuestId(questId);
717-
RolledInstanceWorldQuests[quest.QuestAreaId].Add(quest.QuestScheduleId);
741+
var quest = RollQuestVariant(questId);
742+
if (quest != null)
743+
{
744+
RolledInstanceWorldQuests[quest.QuestAreaId].Add(quest.QuestScheduleId);
745+
}
718746
}
719747
CompletedWorldQuests.Clear();
720748
}
@@ -812,6 +840,45 @@ public SharedQuestStateManager(PartyGroup party, DdonGameServer server)
812840
this.Server = server;
813841
}
814842

843+
public override void EnforceInitialPoolEligibility()
844+
{
845+
var leaderCharacter = Party.Leader?.Client.Character;
846+
if (leaderCharacter == null) return;
847+
848+
lock (ActiveQuests)
849+
{
850+
foreach (var (areaId, scheduleIds) in RolledInstanceWorldQuests)
851+
{
852+
var ineligible = scheduleIds
853+
.Select(id => QuestManager.GetQuestByScheduleId(id))
854+
.Where(q => q != null && q.OrderConditions.Any(c => c.Type == QuestOrderConditionType.AreaRank
855+
&& GetEffectiveAreaRank(leaderCharacter, (QuestAreaId)c.Param01) < (uint)c.Param02))
856+
.ToList();
857+
858+
foreach (var quest in ineligible)
859+
{
860+
scheduleIds.Remove(quest.QuestScheduleId);
861+
var replacement = RollEligibleQuestVariant(quest.QuestId, leaderCharacter);
862+
if (replacement != null)
863+
{
864+
scheduleIds.Add(replacement.QuestScheduleId);
865+
}
866+
}
867+
}
868+
}
869+
}
870+
871+
protected override uint GetEffectiveAreaRank(Character character, QuestAreaId areaId)
872+
{
873+
if (!character.AreaRanks.ContainsKey(areaId)) return 0;
874+
return Server.AreaRankManager.GetEffectiveRank(character, areaId);
875+
}
876+
877+
protected override Quest RollQuestVariant(QuestId questId)
878+
{
879+
return RollEligibleQuestVariant(questId, Party.Leader?.Client.Character);
880+
}
881+
815882
public override bool CompleteQuestProgress(uint questScheduleId, DbConnection? connectionIn = null)
816883
{
817884
Quest quest = GetQuest(questScheduleId);

0 commit comments

Comments
 (0)