Skip to content

Commit 17a7374

Browse files
committed
feat: Implement mutually exclusive quests
Some world quests should not be rolled and active at the same time. Allow a way for these dependencies to be described and give the user a way to override the list via the GameServerSettings.csx. Then on party create and instance reset when the party rolled world quest list is generated/updated, enforce those restrictions for the party.
1 parent 62271d2 commit 17a7374

2 files changed

Lines changed: 98 additions & 0 deletions

File tree

Arrowgene.Ddon.GameServer/Quests/QuestStateManager.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,50 @@ public SharedQuestStateManager(PartyGroup party, DdonGameServer server)
838838
{
839839
this.Party = party;
840840
this.Server = server;
841+
EnforceMutualExclusion();
842+
}
843+
844+
private Dictionary<QuestId, int> BuildMutualExclusionLookup()
845+
{
846+
var lookup = new Dictionary<QuestId, int>();
847+
var groups = Server.GameSettings.GameServerSettings.MutuallyExclusiveWorldQuestGroups;
848+
for (int i = 0; i < groups.Count; i++)
849+
{
850+
foreach (var questId in groups[i])
851+
{
852+
lookup[(QuestId)questId] = i;
853+
}
854+
}
855+
return lookup;
856+
}
857+
858+
private void EnforceMutualExclusion()
859+
{
860+
var lookup = BuildMutualExclusionLookup();
861+
var rolledGroups = new HashSet<int>();
862+
863+
lock (ActiveQuests)
864+
{
865+
foreach (var scheduleIds in RolledInstanceWorldQuests.Values)
866+
{
867+
var toRemove = new List<uint>();
868+
foreach (var scheduleId in scheduleIds)
869+
{
870+
var quest = QuestManager.GetQuestByScheduleId(scheduleId);
871+
if (quest != null && lookup.TryGetValue(quest.QuestId, out int groupIndex))
872+
{
873+
if (!rolledGroups.Add(groupIndex))
874+
{
875+
toRemove.Add(scheduleId);
876+
}
877+
}
878+
}
879+
foreach (var scheduleId in toRemove)
880+
{
881+
scheduleIds.Remove(scheduleId);
882+
}
883+
}
884+
}
841885
}
842886

843887
public override void EnforceInitialPoolEligibility()
@@ -876,9 +920,34 @@ protected override uint GetEffectiveAreaRank(Character character, QuestAreaId ar
876920

877921
protected override Quest RollQuestVariant(QuestId questId)
878922
{
923+
var lookup = BuildMutualExclusionLookup();
924+
if (lookup.TryGetValue(questId, out int groupIndex))
925+
{
926+
var rolledQuestIds = GetRolledQuestIds();
927+
var groups = Server.GameSettings.GameServerSettings.MutuallyExclusiveWorldQuestGroups;
928+
if (groups[groupIndex].Any(gid => (QuestId)gid != questId && rolledQuestIds.Contains((QuestId)gid)))
929+
{
930+
return null;
931+
}
932+
}
879933
return RollEligibleQuestVariant(questId, Party.Leader?.Client.Character);
880934
}
881935

936+
private HashSet<QuestId> GetRolledQuestIds()
937+
{
938+
lock (ActiveQuests)
939+
{
940+
var result = new HashSet<QuestId>();
941+
foreach (var scheduleIds in RolledInstanceWorldQuests.Values)
942+
foreach (var sid in scheduleIds)
943+
{
944+
var quest = QuestManager.GetQuestByScheduleId(sid);
945+
if (quest != null) result.Add(quest.QuestId);
946+
}
947+
return result;
948+
}
949+
}
950+
882951
public override bool CompleteQuestProgress(uint questScheduleId, DbConnection? connectionIn = null)
883952
{
884953
Quest quest = GetQuest(questScheduleId);

Arrowgene.Ddon.Server/Settings/GameServerSettings.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,35 @@ public uint AdventureGuideMaxQuestList
257257
}
258258
private const uint _AdventureGuideMaxQuestList = 50;
259259

260+
/// <summary>
261+
/// Groups of mutually exclusive world quest IDs. When rolling world quests for a party,
262+
/// at most one quest from each group will be selected at a time. Use this to prevent
263+
/// conflicting quests from appearing simultaneously. Quest IDs should be specified as
264+
/// uint values (e.g. 21000079).
265+
/// </summary>
266+
[DefaultValue(
267+
"new List<List<uint>>\n" +
268+
"{\n" +
269+
" new List<uint> { 21000079, 21000089 },\n" +
270+
" new List<uint> { 20995009, 21000008 },\n" +
271+
"}"
272+
)]
273+
public List<List<uint>> MutuallyExclusiveWorldQuestGroups
274+
{
275+
set
276+
{
277+
SetSetting("MutuallyExclusiveWorldQuestGroups", value);
278+
}
279+
get
280+
{
281+
return TryGetSetting("MutuallyExclusiveWorldQuestGroups", new List<List<uint>>
282+
{
283+
new List<uint> { 21000079, 21000089 },
284+
new List<uint> { 20995009, 21000008 },
285+
});
286+
}
287+
}
288+
260289
/// <summary>
261290
/// Uses the automatic exp calculation system for all enemies instead of just using the
262291
/// ones marked in quest files.

0 commit comments

Comments
 (0)