Skip to content

Commit d2b9f7f

Browse files
committed
Tweak distribution for quest generation; block event Hidell Catacombs from being considered for generation. Improve rewards for boss hunt quests while reducing their count.
1 parent 81b3899 commit d2b9f7f

6 files changed

Lines changed: 52 additions & 39 deletions

File tree

Arrowgene.Ddon.GameServer/Handler/QuestGetPartyQuestProgressInfoHandler.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ public override S2CQuestGetPartyQuestProgressInfoRes Handle(GameClient client, C
6464

6565
var questOrder = quest.ToCDataQuestOrderList(questState.Step);
6666

67-
//if (quest.BackingObject is LightQuestHuntQuest lightBackingObject
68-
// && questOrder.QuestProcessStateList.FirstOrDefault()?.WorkList.ElementAtOrDefault(0) != null)
69-
//{
70-
// var huntRecord = questState.HuntRecords.Values.FirstOrDefault();
71-
// questOrder.QuestProcessStateList.FirstOrDefault().WorkList[0] = lightBackingObject.StepAsWork((huntRecord?.AmountHunted ?? 0) + 1);
72-
//}
73-
7467
pcap.QuestOrderList.Add(questOrder);
7568
}
7669

Arrowgene.Ddon.GameServer/Quests/GenericQuest.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,10 @@ public override List<CDataQuestProcessState> StateMachineExecute(DdonGameServer
272272

273273
foreach (var item in questBlock.ConsumePlayerItems)
274274
{
275-
ItemId itemId = (ItemId) item.ItemId;
275+
ItemId itemId = item.ItemId;
276276
if (itemId.IsKeyItem())
277277
{
278-
var items = client.Character.Storage.GetStorage(StorageType.KeyItems).FindItemsById(item.ItemId);
278+
var items = client.Character.Storage.GetStorage(StorageType.KeyItems).FindItemsById((uint)item.ItemId);
279279
if (items.Count == 0)
280280
{
281281
Logger.Error(client, $"The quest {QuestId} was expecting the key item '{itemId}' to be present, but it doesn't exist in the players inventory. Skipping.");
@@ -751,15 +751,6 @@ private static CDataQuestProcessState BlockAsCDataQuestProcessState(GenericQuest
751751
{
752752
// Handles kill x amount of monster type quests
753753
checkCommands.Add(QuestManager.CheckCommand.EmDieLight((int)questBlock.TargetEnemy.EnemyId, (int)questBlock.TargetEnemy.Level, (int)questBlock.TargetEnemy.Amount));
754-
//workCommands.Add(
755-
// new CDataQuestProgressWork()
756-
// {
757-
// CommandNo = (uint)QuestNotifyCommand.KilledEnemyLight,
758-
// Work01 = (int)questBlock.TargetEnemy.EnemyId,
759-
// Work02 = (int)questBlock.TargetEnemy.Level,
760-
// Work03 = 0,
761-
// Work04 = 0,
762-
// });
763754
}
764755
break;
765756
case QuestBlockType.DeliverItemsLight:

Arrowgene.Ddon.GameServer/Quests/LightQuests/LightQuestAreaSummary.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,21 @@ public void Summarize()
3333
}
3434
}
3535

36-
public (EnemyUIId EnemyId, ushort Level) Roll(HashSet<EnemyUIId> exceptions = null)
36+
public LightQuestAreaHuntSummaryRecord Roll(HashSet<EnemyUIId> exceptions = null)
3737
{
3838
var enemies = HuntRecords.Values.Where(x => exceptions is null || !exceptions.Contains(x.EnemyUIId)).ToList();
3939
var weights = enemies.Select(x => x.Weight).ToList();
4040

4141
if (enemies.Count == 0)
4242
{
4343
// Failure; no valid enemies.
44-
return (0, 0);
44+
return null;
4545
}
4646

4747
var chosenRecord = Random.Shared.ChooseWeighted(enemies, weights);
4848
var chosenLevel = chosenRecord.RollLevel();
4949

50-
return (chosenRecord.EnemyUIId, chosenLevel);
50+
return chosenRecord;
5151
}
5252

5353
}
@@ -63,6 +63,8 @@ public class LightQuestAreaHuntSummaryRecord(EnemyUIId enemyUIId)
6363
public double MeanLevel { get; set; }
6464
public double StdLevel { get; set; }
6565

66+
public double Difficulty { get { return ((double)BossCount) / Count; } }
67+
6668
private List<(ushort Level, bool IsBoss)> EnemyData { get; set; } = [];
6769

6870
public void Summarize()
@@ -95,8 +97,11 @@ public double Weight
9597

9698
public ushort RollLevel()
9799
{
98-
double randNormal = Random.Shared.NextNormal(MeanLevel, StdLevel);
99-
ushort chosenLevel = (ushort)Math.Round(Math.Clamp(randNormal, ExtantLevels.Min(), ExtantLevels.Max()));
100+
uint minLevel = ExtantLevels.Min();
101+
double p = 1.0 / (1 + MeanLevel - minLevel);
102+
long randGeo = Random.Shared.NextGeometric(p) + minLevel;
103+
//double randNormal = Random.Shared.NextNormal(MeanLevel, StdLevel);
104+
ushort chosenLevel = (ushort)Math.Clamp(randGeo, ExtantLevels.Min(), ExtantLevels.Max());
100105
if (!ExtantLevels.Contains(chosenLevel))
101106
{
102107
// Round down to the next lowest extant level

Arrowgene.Ddon.GameServer/Quests/LightQuests/LightQuestManager.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,16 @@ private LightQuestRecord RollHuntQuest(LightQuestInfo quest, LightQuestGeneratin
132132
int attempt = 0;
133133
while (attempt < GENERATOR_ATTEMPTS_PER_QUEST)
134134
{
135-
List<(EnemyUIId, ushort)> biasRolls = [];
135+
List<(LightQuestAreaHuntSummaryRecord Record, ushort Level)> biasRolls = [];
136136
for (int biasRoll = 0; biasRoll <= generatingAsset.BiasRerolls; biasRoll++)
137137
{
138-
var (rollEnemy, rollLevel) = summary.Roll(rolledEnemyIds);
139-
if (rollEnemy == 0)
138+
var rollRecord = summary.Roll(rolledEnemyIds);
139+
if (rollRecord is null)
140140
{
141141
Logger.Error($"Error in generator {generatingAsset.Name}; no valid enemies for region.");
142142
break;
143143
}
144-
biasRolls.Add((rollEnemy, rollLevel));
144+
biasRolls.Add((rollRecord, rollRecord.RollLevel()));
145145
}
146146

147147
if (biasRolls.Count == 0)
@@ -153,19 +153,23 @@ private LightQuestRecord RollHuntQuest(LightQuestInfo quest, LightQuestGeneratin
153153

154154
if (generatingAsset.BiasLower)
155155
{
156-
biasRolls = biasRolls.OrderBy(x => x.Item2).ToList();
156+
biasRolls = [.. biasRolls.OrderBy(x => x.Level)];
157157
}
158158
else
159159
{
160-
biasRolls = biasRolls.OrderByDescending(x => x.Item2).ToList();
160+
biasRolls = [.. biasRolls.OrderByDescending(x => x.Level)];
161161
}
162162

163-
var chosenRoll = biasRolls.First();
163+
var (chosenRecord, chosenLevel) = biasRolls.First();
164164

165-
if (generatingAsset.MinLevel <= chosenRoll.Item2 && chosenRoll.Item2 <= generatingAsset.MaxLevel)
165+
if (generatingAsset.MinLevel <= chosenLevel && chosenLevel <= generatingAsset.MaxLevel)
166166
{
167167
var mixin = Server.ScriptManager.MixinModule.Get<ILightQuestRewardMixin>("light_hunt_quest_reward");
168-
finalRecord = FinalizeRecord(quest, generatingAsset, (int)chosenRoll.Item1, chosenRoll.Item2, mixin);
168+
finalRecord = FinalizeRecord(quest, generatingAsset, (int)chosenRecord.EnemyUIId, chosenLevel, mixin, chosenRecord.Difficulty);
169+
170+
// Adjustment of count for boss hunts; applies after the rewards are counted.
171+
finalRecord.Count = (int)Math.Pow(finalRecord.Count, 1.0 / (1 + chosenRecord.Difficulty));
172+
169173
break;
170174
}
171175

@@ -233,7 +237,7 @@ private LightQuestRecord RollDeliveryQuest(LightQuestInfo quest, LightQuestGener
233237
return finalRecord;
234238
}
235239

236-
private LightQuestRecord FinalizeRecord(LightQuestInfo quest, LightQuestGeneratingAsset generatingAsset, int target, ushort level, ILightQuestRewardMixin mixin)
240+
private LightQuestRecord FinalizeRecord(LightQuestInfo quest, LightQuestGeneratingAsset generatingAsset, int target, ushort level, ILightQuestRewardMixin mixin, double difficulty = 0.0)
237241
{
238242
var finalRecord = new LightQuestRecord()
239243
{
@@ -246,10 +250,10 @@ private LightQuestRecord FinalizeRecord(LightQuestInfo quest, LightQuestGenerati
246250
DistributionEnd = DateTimeOffset.UtcNow + BOARD_QUEST_DURATION
247251
};
248252

249-
finalRecord.RewardG = mixin.CalculateRewardG(finalRecord);
250-
finalRecord.RewardR = mixin.CalculateRewardR(finalRecord);
251-
finalRecord.RewardXP = mixin.CalculateRewardXP(finalRecord);
252-
finalRecord.RewardAP = mixin.CalculateRewardAP(finalRecord);
253+
finalRecord.RewardG = mixin.CalculateRewardG(finalRecord, difficulty);
254+
finalRecord.RewardR = mixin.CalculateRewardR(finalRecord, difficulty);
255+
finalRecord.RewardXP = mixin.CalculateRewardXP(finalRecord, difficulty);
256+
finalRecord.RewardAP = mixin.CalculateRewardAP(finalRecord, difficulty);
253257

254258
string targetString = quest.Type == LightQuestType.Hunt ? ((EnemyUIId)target).ToString() : ((ItemId)target).ToString();
255259

@@ -587,7 +591,8 @@ private void HandleEnemy(Enemy enemy, LightQuestAreaHuntSummary huntSummary, Lig
587591
Stage.GardnoxWastewaterTunnel,
588592
Stage.PitofScreams,
589593
Stage.MysteriousMausoleum,
590-
Stage.SecretProvingGround
594+
Stage.SecretProvingGround,
595+
Stage.HidellCatacombs1
591596
}.Select(x => x.StageId).ToHashSet();
592597

593598
private static readonly HashSet<ItemSubCategory> DeliverableSubCategories =

Arrowgene.Ddon.GameServer/Utils/RandomExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ public static double NextNormal(this Random rnd, double mean, double std)
6969
return mean + std * randStdNormal; //random normal(mean,stdDev^2)
7070
}
7171

72+
/// <summary>
73+
/// Random geometric variates.
74+
/// </summary>
75+
/// <param name="rnd"></param>
76+
/// <param name="p"></param>
77+
/// <returns></returns>
78+
/// <exception cref="ArgumentException"></exception>
79+
public static int NextGeometric(this Random rnd, double p)
80+
{
81+
if (p <= 0 || p > 1)
82+
{
83+
throw new ArgumentException("Invalid probability for geometric distribution. (0 < p <= 1)");
84+
}
85+
double u = rnd.NextDouble();
86+
double lnu = Math.Log(u);
87+
double lnp = Math.Log(1 - p);
88+
return (int)Math.Floor(lnu / lnp);
89+
}
90+
7291
/// <summary>
7392
/// Choose from a list of objects according to their weights.
7493
/// </summary>

Arrowgene.Ddon.Scripts/scripts/mixins/light_hunt_quest_reward.csx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class Mixin : ILightQuestRewardMixin
1515
// More generous at most levels, less generous at the jumps.
1616
double baseXP = 1.150 * Math.Pow(level, 2.0) + 100;
1717

18-
double difficultyFactor = difficulty * 7.0 + 1.0;
18+
double difficultyFactor = difficulty * 9.0 + 1.0;
1919

2020
return (uint)(baseXP * adjustedCount * difficultyFactor);
2121
}

0 commit comments

Comments
 (0)