Page 1 of 1
Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 3:29 am
by angrynorwegian13
I've gone through tons of posts about loot generator problems and things like that here on the forums but haven't found a solution to this problem...The loot on my server works, but it seems theres a problem with the way it calculates what loot to drop. For instance on one mob that is supposed to drop 11 items (8 "seals", like diamond seals and 3 pieces of gear), he drops no seals at all, 8 of the same piece of gear and then 3 random pieces of gear, which looks kinda like this in game:
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Magical Belt.
Mob drops Sword of fire.
Mob drops Magic Large shield.
Mob drops Ring of Awesome.
Mob drops bag of coins.
The chance to drop the belt isn't even very large, its like a 30% chance, and on the list of items that the mob drops (/mob viewloot) its in the middle. There are "seals" on there that have 100% chance to drop that don't even drop. Theres about 15 different pieces of gear that could drop off this mob and every time he drops 8 of the same item and then 3 random ones. Again, it seems like theres a problem in the way the game calculates which pieces of gear are supposed to drop and I was curious if anyone has a working code that I can replace the current code with. All i need is for the mob to drop 8 seperate "seals" (I realize I could put 8 in one stack but this is a group mob and i want the items to be split between the group) and 3 or so pieces of gear. I've looked in the loottemplate table and everything is fine. All the items im using are custom and they are all correctly linked with the itemtemplate table and show up in game under /mob viewloot also. I've tried replacing the code in my lootlist.cs with a couple different things I've found on the forums already but nothing has worked yet, which is why I made a post about it. Thanks for any help.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 8:19 am
by Dinberg
Are you using the DoL standard loot generator? what is the files name?
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 2:31 pm
by Tired
Everytime, you must understand... it's a calculation. It could drop anything at any point in time. If you have something set to 90% and one thing set to 10%. It could drop the 10% one 2x in a row or even 4x in a row. That's all it is, a calculation. Math sometimes doesn't make sense but we all can't live without it. It's just a chance for it.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 3:36 pm
by Dinberg
Try setting the MaxCount on the belt object to 1, see if that works
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 4:05 pm
by Batlas
If I remember correctly someone had made a suggestion to set all the time items drop % to > 100. I'm not too sure of the legitimacy of this as I never played with drops.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 5:36 pm
by Tolakram
I have always suspected something is really wrong with the lootlist. The logic is crazy non-intuitive when what it's trying to do is so simple, plus I think this piece of code might be the problem.
https://dolserver.svn.sourceforge.net/s ... ootList.cs
- Code: Select all
public ItemTemplate[] GetLoot()
{
ArrayList loot = new ArrayList(m_fixedItemDrops.Count + m_dropCount);
loot.AddRange(m_fixedItemDrops);
int dice;
ArrayList lootCandidates = new ArrayList();
if ( m_dropCount != 0)
{
// Big logic change. The intended flow of the original code was to iterate over the drop list
// DropCount times, each iteration doing the following:
// 1.) clear lootCandidates array
// 2.) for each loot item in m_randomItemDrops roll D100 against frequency
// 3.) each winner gts into lootCandidates array
// 4.) pick one random winner out of lootCandidates, add to the returned loot list
// The bug reported was caused by the loot.Add being outside the main loop. only
// the last winner made it into the loot array that is returned.
// There is a secondary defect that surfaces once the loop issue is fixed. There is
// a high chance of duplicate items dropping. This is counter to live game server
// behavior.
//
// New logic iterates once accross m_randomItemDrops, rolling D100 against frequency.
// Winner items are placed into lootCandidates. Once that loop is complete, we enter
// into a second loop. In each iteration, we select one random winner from lootCandidates,
// add it the to returned loot array, then remove it from lootCandidates. This avoids
// code-induced duplicates. I imagine that ArrayList.RemoveAt() is a little expensive on cpu
// cycles as it has to collapse the array each time an item is removed. A second option is
// to build a matching array of booleans, set all to false, and each time a winner is copied
// to loot, set the value in the matching array at the same index value to true. This introduces
// the need for a nested loop to avoid true values in the matching array, and if not coded properly,
// will hang the server as it loops an infinite number of times. The third option is to ignore
// all of this, say that dupes are o.k., pull loot.Add inside the main loop of the old code
// and move on.
// new logic
lootCandidates.Clear();
foreach (LootEntry lootEntry in m_randomItemDrops)
{
dice = Util.Random(1, 100);
if (lootEntry.Chance >= dice)
lootCandidates.Add(lootEntry.ItemTemplate);
}
// At this point, the candidate list is filled with items that passed
// the %chance to drop, so we need to put DropCount of them into the return loot object.
//
// Initial control thought is to use the ArrayList.RemoveAt method and change the loop control
// to include a check on lootCandidates.Count. This assumes that the removeAt function re-builds
// the array and updates ArrayList.Count. If not, we'll be throwing exceptions like mad.
// copy random winners to returned loot list
if (lootCandidates.Count > 0)
{
for (int i = 0; (i < m_dropCount && lootCandidates.Count != 0); i++)
{
int tmpidx;
tmpidx = Util.Random(lootCandidates.Count - 1);
loot.Add(lootCandidates[tmpidx]);
lootCandidates.RemoveAt(tmpidx);
}
}
}
return (ItemTemplate[])loot.ToArray(typeof(ItemTemplate));
}
}
Here's the problem as I see it.
Let's say you have 5 pieces of loot attached to a mob. 4 pieces have a 25% chance to drop, 1 piece has only a 5% chance to drop. On the creation of the loot candidate list the first 4 pieces have a 25% chance of getting into the list, the last piece a 5% chance. But then only 1 drop is chosen from the list, which makes rare drops
exceedingly rare, especially if there are numerous drops for the same mob and those drops have a higher chance to drop.
I'm not sure I'm capable of doing the math for this but I suspect that 5% item, since it's only 1 drop in 5 total, really has less than a 2.5% chance to drop because the other items have a higher chance and occur more often. The chance falloff rate is exponential.
I think this routine should create a candidate list like it does, but then weight the drop based on the rarity. Perhaps only chancing again if the drop chance for the items are the same, otherwise drop the lowest chance loot that makes it to the candidate list. This would still not be perfect, but at least the 5% drop really has a 5% chance to drop.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 7:01 pm
by Batlas
If we wanted to make it work in a better situation. What we could do is all 100% items will be added to the list first. These will always drop (and theoretically should not be included in the items count.) From there we would go with the lowest % of item to drop up to the highest %. This way the low drops will have a greater chance of dropping off said mobs. Capiche?
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 7:17 pm
by Graveen
extra !
droplist = items evaluated from 1 to 99%. Once the dropcount is reached, add 100%
and otd ? they are handled directly in the inventory iirc, not a bag on the floor ? a quest ? could be integrated in lootlist & flaggued correctly as an otd.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 7:46 pm
by Tolakram
100% is added to fixed, but the problem still applies to multiple items. Basically if you want to add multiple non 100% items to a mob and you want it to have the stated chance to drop then make sure every <100% item added to that mob has the exact same % chance to drop.
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 9:16 pm
by Graveen
Sure the "2 pass system" is really faking the toss (1st pass to see what items are winning the toss, second passto randomly choose about items).
I like the Batlas idea, because items are browsed in rising orders, but the same problem should happen in case you have - let's approximate - a long linear list: Gaussian , so all items should be mainly dropped around 35-65%.
Perhaps the
- chance to drop % and chance to be in (100/total drop list) % and chance to be in (100/dropcount) %
could on normal list give statistically a #dropcount loot to drop ?
Re: Working Loot Calculation Code
PostPosted: Mon Apr 13, 2009 9:24 pm
by Kakuri
The current loot code is really screwy and could use an overhaul.
I like Batlas' idea - start with the lower % items first, then work your way up until you reach DropCount. And of course, 100% items should always drop, even if DropCount has been exceeded. If you don't want the item to drop 100% of the time, don't set the chance to 100%. The current loot code will not drop 100% items 100% of the time.
Re: Working Loot Calculation Code
PostPosted: Thu Apr 16, 2009 7:21 am
by Kakuri
I have redone the Loot Generator Template to work as follows:
DropCount has been removed (by the way, how's this for making sense: the way DropCount worked was that any item with a 100% drop rate would be added to the loot DropCount times).
To replace DropCount I have added MinDrops and MaxDrops to the mobxloottemplate table. To continue to have behavior similar to current behavior, set MinDrops=0 and MaxDrops=DropCount. A minimum of MinDrops items will drop (even if you only have one item in the template - it will be dropped MinDrops times). If you have more items in the template than MaxDrops, then up to, but not necessarily equal to, MaxDrops will drop. It depends on the chance - if the items have high chances, then there's a better chance you'll get MaxDrops items. If they have low chances, then you'll generally be closer to MinDrops number of items.
Items set to 100% don't affect MinDrops/MaxDrops - they are guaranteed to drop.
There was, and remains, a lazy relationship between mob name and item drops. The first check is to find a loot template associated with the mob's name in mobxloottemplate. A large number of mobs in the db have no corresponding entry in mobxloottemplate. Instead, the loottemplate itself has the same name as the mob, so we look for any entries in the loottemplate table that match the mob's name. Since there is no entry in mobxloottemplate, MinDrops and MaxDrops don't apply - default values of 0 and 2 are used.
The first loop goes through all items, starting with the lowest chance items, and does a random roll to see if they get included. After a single loop through all items, if we have met or exceeded MinDrops, then we're done. We may still be below MaxDrops.
If we're still below MinDrops, then another loop goes through the remaining items and keeps rolling against them to include more until MinDrops is met. To ensure this loop doesn't continue excessively long, if a number of iterations (currently set to 50) fails to populate the loot with MinDrops, then we stop rolling against each item's chance and instead just add them to the loot.
Re: Working Loot Calculation Code
PostPosted: Fri Apr 17, 2009 1:47 am
by Kakuri
In case anyone's curious, I ran an analysis of the loot templates (from Storm, my database is a few months old though) to see if they could be optimized - not much of the "template" functionality is being taken advantage of. Almost every single mob has its own loot template, and many have no template at all, just plain entries in the loottemplate table. So I wanted to see if the entries in both tables could be reduced by actually using templates, so mobs with the same droplist would use the same template. It turns out most mobs have unique droplists. There are 323 mobs with entries in mobxloottemplate that have no corresponding entries in loottemplate, so these mobs drop no loot and waste a bit of space in the mobxloottemplate table. There are 50 mobs that simply drop a diamond seal that could all share the same template, but instead they each have a unique template. Other than that, it doesn't seem like there's very significant optimizations to be made - you can see below there's a fair number of droplists shared by 2 or 3 mobs, but overall I think the impact is pretty insignificant (compared to the 2700+ loot templates and 15000+ items dropped).
The "report" (it's pretty rough, but tells me the basics of the info I wanted) below shows the name of a mob and the number of other mobs with the same droplist (who each have their own copy of the droplist, instead of sharing a template). At the bottom are some entries with "orphan" after the mob's name - this just means the drops are in the loottemplate table, but there's no entry in mobxloottemplate (which works OK, but it's better to have the entry in mobxloottemplate).
- Code: Select all
19:41:24,048 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - experienced necyomancer count = 24
19:41:24,048 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - arcere decaduto count = 4
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - grand chancellor adremal count = 323
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - clay jotun runner count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - dastur count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - blodfelag soothsayer count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - frit count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - virilus count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - ostadi count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Inquisitor Morrian count = 50
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - sett matron count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - naburite drinker count = 6
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - sidhe draoi count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - pendragon ardent count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - gorgon stalker count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - yar count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - karise count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - soldato spettrale decaduto count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - mangled troll invader count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - igo count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - blindsnake count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - lurker count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - uaimh forager count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - hoiples count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - ibn count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - suralle count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - spiteful wraith count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - General Korand count = 18
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - lady leana count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - arachite greensilk count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - wyulv count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - bottom feeder count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - svartalf sorcerer count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - kasora count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - shadowhunter count = 5
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - fomorian xexen count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - aqueous slug count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - wood-eater queen count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - mountain mephit count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - gala count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - small hill cat count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar belladonna count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - ellyll explorer count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - wood-eater worker count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar warrior count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Sylver count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - deep shrouder count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - gemclicker horder count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - slythcur count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - moor wolf count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - shyene muire count = 6
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar tracker count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - uaimh delver count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar twister count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar tainter count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar stonemelder count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar spikelord count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - olcasar mystic count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - hypogean beast count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - flesh stripper count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - blue cattail sporite count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - balorian liosliath count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - goblin snatcher count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - winter wolf count = 4
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - mud crab warrior count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - lord dasirual count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - merrow maiden count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - torc count = 7
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - urchin scavenger count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - scratchfoot scrounger count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - kaen kedger count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - curmudgeon rockclimber count = 4
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - grundor count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - chaplain count = 4
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - gardener count = 4
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - gwacka tree count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - zombie count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - muire head butler count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - fenrir tracker count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Golestandt count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Golestandt count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - soth count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Urgan Ulgeth count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Urgan Golr count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Urgan Nalkagh count = 2
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Mevos count = 3
19:41:24,064 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Selsan Solis count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Virilis orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Soulsinger Arthim orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - High Lord Baln orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Grundor orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Prugor orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Sephucoth orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - manta ray orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - umbrood warrior orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - Lady Leana orphaned count = 2
19:41:26,158 - [MAIN] - INFO - DOL.GS.LootGeneratorTemplate - manowar orphaned count = 2