[Bug] Loot Drop Randomization adjustment (#2368)

* [Bug] Loot Drop Randomization adjustment

Loot Table currently favors the first item in the loot drop. This should help remove that condition.

Code by Ailia.

* snake_case

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Michael 2022-08-31 00:31:07 -04:00 committed by GitHub
parent 149fa54cfa
commit 3228d6edf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -165,11 +165,20 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
} }
float roll_t = 0.0f; float roll_t = 0.0f;
float no_loot_prob = 1.0f;
bool roll_table_chance_bypass = false;
bool active_item_list = false; bool active_item_list = false;
for (uint32 i = 0; i < loot_drop->NumEntries; ++i) { for (uint32 i = 0; i < loot_drop->NumEntries; ++i) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[i].item_id); const EQ::ItemData *db_item = GetItem(loot_drop->Entries[i].item_id);
if (db_item && npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i])) { if (db_item && npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i])) {
roll_t += loot_drop->Entries[i].chance; roll_t += loot_drop->Entries[i].chance;
if (loot_drop->Entries[i].chance >= 100) {
roll_table_chance_bypass = true;
}
else {
no_loot_prob *= (100 - loot_drop->Entries[i].chance) / 100.0f;
}
active_item_list = true; active_item_list = true;
} }
} }
@ -183,14 +192,18 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
// The roll isn't 0-100, its 0-total and it picks the item, we're just // The roll isn't 0-100, its 0-total and it picks the item, we're just
// looping to find the lucky item, descremening otherwise. This is ok, // looping to find the lucky item, descremening otherwise. This is ok,
// items with chance 60 are 6 times more likely than items chance 10. // items with chance 60 are 6 times more likely than items chance 10.
for (int i = 0; i < mindrop; ++i) { int drops = 0;
for (int i = 0; i < droplimit; ++i) {
if (drops < mindrop || roll_table_chance_bypass || (float) zone->random.Real(0.0, 1.0) >= no_loot_prob) {
float roll = (float) zone->random.Real(0.0, roll_t); float roll = (float) zone->random.Real(0.0, roll_t);
for (uint32 j = 0; j < loot_drop->NumEntries; ++j) { for (uint32 j = 0; j < loot_drop->NumEntries; ++j) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[j].item_id); const EQ::ItemData *db_item = GetItem(loot_drop->Entries[j].item_id);
if (db_item) { if (db_item) {
// if it doesn't meet the requirements do nothing // if it doesn't meet the requirements do nothing
if (!npc->MeetsLootDropLevelRequirements(loot_drop->Entries[j])) if (!npc->MeetsLootDropLevelRequirements(loot_drop->Entries[j])) {
continue; continue;
}
if (roll < loot_drop->Entries[j].chance) { if (roll < loot_drop->Entries[j].chance) {
npc->AddLootDrop( npc->AddLootDrop(
@ -198,6 +211,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
item_list, item_list,
loot_drop->Entries[j] loot_drop->Entries[j]
); );
drops++;
int charges = (int) loot_drop->Entries[i].multiplier; int charges = (int) loot_drop->Entries[i].multiplier;
charges = EQ::ClampLower(charges, 1); charges = EQ::ClampLower(charges, 1);
@ -222,65 +236,8 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
} }
} }
} }
// Now that mindrop has been established see if we get any more based
// on item odds. Pick a random entry to start at so no one entry is favored.
// Look at all items until we hit droplimit or look at all items.
if (droplimit <= mindrop) {
return;
} }
int start_index = zone->random.Int(0,loot_drop->NumEntries-1);
int j = start_index;
int dropped = mindrop;
do {
LogLootDetail("DropLimit Starting at [{}] out of [{}]", j,
loot_drop->NumEntries);
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[j].item_id);
if (db_item &&
npc->MeetsLootDropLevelRequirements(loot_drop->Entries[j])) {
float iroll = (float) zone->random.Real(0.0, 100.0);
LogLootDetail("Rolled [{}] Needed [{}]", iroll, loot_drop->Entries[j].chance);
// If this item succeeds the chance roll
if (iroll < loot_drop->Entries[j].chance) {
++dropped;
LogLootDetail("Dropping item [{}]", loot_drop->Entries[j].item_id);
npc->AddLootDrop(
db_item,
item_list,
loot_drop->Entries[j]
);
int charges = (int) loot_drop->Entries[j].multiplier;
charges = EQ::ClampLower(charges, 1);
for (int k = 1; k < charges; ++k) {
float c_roll = (float) zone->random.Real(0.0, 100.0);
if (c_roll <= loot_drop->Entries[j].chance) {
npc->AddLootDrop(
db_item,
item_list,
loot_drop->Entries[j]
);
}
}
}
}
// Wrap the loop back to catch the start of loop
if (++j >= loot_drop->NumEntries) {
j = 0;
}
} while (dropped < droplimit && j != start_index);
npc->UpdateEquipmentLight(); npc->UpdateEquipmentLight();
// no wearchange associated with this function..so, this should not be needed // no wearchange associated with this function..so, this should not be needed
//if (npc->UpdateActiveLightValue()) //if (npc->UpdateActiveLightValue())