Thread: Loottables
View Single Post
  #9  
Old 06-07-2011, 08:51 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Here is the code that handles the loot drops being added. Note the part highlighted in green where it picks a random entry from the total number of entries to start at and resets it back to 0 if it rolls past the end of the list.

loottables.cpp
Code:
// Called by AddLootTableToNPC
// maxdrops = size of the array npcd
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;

// This is Wiz's updated Pool Looting functionality.  Eventually, the database format should be moved over to use this
// or implemented to support both methods.  (A unique identifier in lootable_entries indicates to roll for a pool item
// in another table.
#ifdef POOLLOOTING
        printf("POOL!\n");
        int32 chancepool = 0;
        int32 loot_items[100];
        int8  equipitem[100];
        int32 itemchance[100];
        int16 itemcharges[100];
        int8 i = 0;

        for (int m=0;m < 100;m++) {
                loot_items[m]=0;
                itemchance[m]=0;
                itemcharges[m]=0;
                equipitem[m]=0;
        }

        for (int k=0; k<lds->NumEntries; k++)
        {
                loot_items[i] = lds->Entries[k].item_id;
                int chance = lds->Entries[k].chance;
                itemcharges[i] = lds->Entries[k].item_charges;
                equipitem[i] = lds->Entries[k].equip_item;

                /*
                im not sure what this is trying to accomplish...
                LinkedListIterator<ServerLootItem_Struct*> iterator(*itemlist);
                iterator.Reset();
                while(iterator.MoreElements())
                {
                         if (iterator.GetData()->item_id == loot_items[i])
                         {
                                chance /= 5;
                         }
                         iterator.Advance();
                }*/

                chance += chancepool;
                chancepool += lds->Entries[k].chance;
                itemchance[i] = chance;
                i++;
        }
        int32 res;
        i = 0;

    if (chancepool!=0) { //avoid divide by zero if some mobs have 0 for chancepool
        res = MakeRandomInt(0, chancepool-1);
    }
    else {
        res = 0;
    }

        while (loot_items[i] != 0) {
                if (res <= itemchance[i])
                        break;
                else
                        i++;
        }
        const Item_Struct* dbitem = GetItem(items[i]);
        npc->AddLootDrop(dbitem, itemlist, lds->Entries[k].item_charges, lds->Entries[k].equip_item, false);

#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 = MakeRandomInt(0, totalchance-1);
#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++;    //Cycle to the next droppable item in the list
        }       //end loop
#endif

}
This should prevent it from favoring items at the top of the list. It has been a while since I really looked into how these are all handled (not since that old thread Zothen referred to), but I think the way I described things so far in this thread should be accurate.

And yes, Zothen, your example of having 3 drops from that setup is correct. With those settings, you could have either 2 or 3 drops, depending on if the 50% probability one wins the roll or not.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 06-07-2011 at 08:57 AM..
Reply With Quote