Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Bug Reports

Development::Bug Reports Post detailed bug reports and what you would like to see next in the emu here.

Reply
 
Thread Tools Display Modes
  #1  
Old 11-23-2009, 07:08 AM
iggi
Sarnak
 
Join Date: Feb 2006
Posts: 62
Default

EDIT- This got deleted in my previous post when editing:

randnum % loottablesize = number of drops
(optional)number of drops = number of drops * frequency modifier
while(number of drops > 0){
randnum % loottablesize = item picked
randnum % 10 = (actual)randnumber
if ((actual)randnumber <= (probability*10) ){ \\assuming probability is in decimal
drop(item picked);
}
number of drops--;
}

If you wanted to add a weight to number of drops, you can always use this pseudo code again accounting for the weighted drops instead of probability of drops.
Reply With Quote
  #2  
Old 01-15-2010, 08:31 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

After looking at this again, maybe trying a slight modification like this would work.

Change the part in Red here from zone/loottables.cpp:

Code:
void ZoneDatabase::AddLootDropToNPC(NPC* npc,int32 lootdrop_id, ItemList* itemlist) {
	const LootDrop_Struct* lds = GetLootDrop(lootdrop_id);
	if (!lds) {
	 //   LogFile->write(EQEMuLog::Error, "Database Or Memory error GetLootDrop(%i) == 0, npc:%s", lootdrop_id, npc->GetName());
		return;
	}
	if(lds->NumEntries == 0)	//nothing possible to add
		return;

//Removed code for pool looting which isn't applicable to this example

#else
	//non-pool based looting

	int32 r;
	int32 totalchance = 0;
	for (r = 0; r < lds->NumEntries; r++) {
		totalchance += lds->Entries[r].chance;
	}
	uint32 thischance = 0;
	unsigned short k;
	bool found = false;
	
	while(!found) {
		k = MakeRandomInt(0, lds->NumEntries-1);
		
		thischance = lds->Entries[k].chance;
		unsigned int drop_chance = rand() % totalchance;
#if EQDEBUG>=11
			LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, total chance:%i this chance:%i, drop roll:%i", npc->GetName(), totalchance, thischance, drop_chance);
#endif
		if (   totalchance == 0 
			|| thischance == 100
			|| thischance == totalchance // only droppable item in loot table
			|| drop_chance < thischance	//can never be true if thischance is 0
			) {
			found = true;
			int32 itemid = lds->Entries[k].item_id;
			
			const Item_Struct* dbitem = GetItem(itemid);
			npc->AddLootDrop(dbitem, itemlist, lds->Entries[k].item_charges, lds->Entries[k].equip_item, false);
			
			break;
			//continue;
		}	//end if it will drop
	}	//end loop
#endif
Into the part in blue here:

Code:
void ZoneDatabase::AddLootDropToNPC(NPC* npc,int32 lootdrop_id, ItemList* itemlist) {
	const LootDrop_Struct* lds = GetLootDrop(lootdrop_id);
	if (!lds) {
	 //   LogFile->write(EQEMuLog::Error, "Database Or Memory error GetLootDrop(%i) == 0, npc:%s", lootdrop_id, npc->GetName());
		return;
	}
	if(lds->NumEntries == 0)	//nothing possible to add
		return;

//Removed code for pool looting which isn't applicable to this example

#else
	//non-pool based looting

	int32 r;
	int32 totalchance = 0;
	for (r = 0; r < lds->NumEntries; r++) {
		totalchance += lds->Entries[r].chance;
	}
	uint32 thischance = 0;
	unsigned short k;
	bool found = false;
	
	k = MakeRandomInt(0, lds->NumEntries-1);

	while(!found) {
		if (k > (lds->NumEntries - 1)) {
			k = 0;
		}

		thischance = lds->Entries[k].chance;
		unsigned int drop_chance = rand() % totalchance;
#if EQDEBUG>=11
			LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, total chance:%i this chance:%i, drop roll:%i", npc->GetName(), totalchance, thischance, drop_chance);
#endif
		if (   totalchance == 0 
			|| thischance == 100
			|| thischance == totalchance // only droppable item in loot table
			|| drop_chance < thischance	//can never be true if thischance is 0
			) {
			found = true;
			int32 itemid = lds->Entries[k].item_id;
			
			const Item_Struct* dbitem = GetItem(itemid);
			npc->AddLootDrop(dbitem, itemlist, lds->Entries[k].item_charges, lds->Entries[k].equip_item, false);
			
			break;
			//continue;
		}	//end if it will drop
		k++;
	}	//end loop
#endif
Basically, what that will do is to make it so it only runs the RNG 1 time to decide the starting point to loop through the table entries. That is apposed to using the RNG every time it loops to chose a random entry to check if it will drop or not.

If there is an issue with the loot drop system, as far as I can tell, it would have to be due to the RNG itself. I think it is pretty well-known that the RNG is never as random as it really should be. This will at least prevent the RNG from repeatedly hitting the same drop over and over as it decides loot. There will still be RNG involved, but this should at least force it to continue down the list after it selects the random starting entry to check first.

I have personally seen some drop issues that point to there being a definite problem with drop rates. I think that it may work fine when repopping the same NPC over and over as in the example Cavedude gave. But, my theory is that the problem is something to do with server or zone restarts that cause it to give preference to certain drops for the first time a NPC spawns after a zone/server restart. I don't know why that would be the case, but that is just my best guess.

Either way, it might be worth giving this a long test to see if there is any improvement through feedback of players and testing and such.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 01-20-2010 at 10:23 PM..
Reply With Quote
  #3  
Old 01-17-2010, 11:32 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Well, I got this change added to run on Storm Haven currently for the past week and it seems to be working at least as well as the original way. I won't put this change on the SVN without approval from KLS or Derision or someone like that, though. I want them to see what they think first before changing something this essential that has the potential to cause issues with players.

I think that this might be a better way to handle doing loot tables. Instead of the previous way, where it used the RNG every time to select which item to check if it will drop, it would now only RNG to pick the item in the list to start checking at and then continue down the list and cycle through it until one of them is successfully picked. This just takes 1 step of the RNG out of the picture and since the RNG is known to not truely be as random as it should be, I think that would be a good thing to help make drop rates closer to being exactly what they should be.

While discussing this on my own forums, I came up with an idea that might be useful. The idea would be to write a new quest command that will let you get a list of all of the items currently on an NPC at any particular time. So, you could use it to get a list of items on an NPC at the time it is killed and then use quest::write() to write the list to a file. By doing this, you could log certain NPCs that are killed regularly and then over time you could get enough data to have a pretty clear picture on if drop rates are actually what they should be. Another use of being able to get the list of loot on an NPC would be to keep track of what drops were on an NPC when it was killed, for certain high end bosses. I know I have had cases where zone crashes were occurring due to certain issues and people wouldn't get to loot items. At least with this, I would have been able to confirm which items actually dropped or should have dropped before the crash occurred.

Now, I just gotta think of a way to get that list and make it into something that can be used in perl. Maybe exporting them to an array would work, or even just set them all into string or something.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #4  
Old 01-19-2010, 02:12 AM
AndMetal
Developer
 
Join Date: Mar 2007
Location: Ohio
Posts: 648
Default

Quote:
Originally Posted by trevius View Post
Now, I just gotta think of a way to get that list and make it into something that can be used in perl. Maybe exporting them to an array would work, or even just set them all into string or something.
Array + 1.
__________________
GM-Impossible of 'A work in progress'
A non-legit PEQ DB server
How to create your own non-legit server

My Contributions to the Wiki
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 03:48 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3