Creating a Loot Table

From Multiverse

(Redirected from Loot Table)
Jump to: navigation, search
The code in this article or section has not been verified with Multiverse platform version 1.5. You can help by testing it, and rewriting as necessary.

Contents

Introduction

Note: This work was done during the beta of the platform, it has not been tested under the 1.0+ release but it should work.

I created a system of for loot tables a long time ago for my project while the MV code was still in beta. It is fairly simple, you assign the loot table to the template, and the items that the mob has on it is decided on the fly when the mob is generated. It supports any number of different sets of items, and allows you to assign the percentage chance of each spawning on the mob you are associating with it. With a little work it could be easily extended to allow re-use of loot tables between multiple templates if you really wanted.

The following code would be added directly to each mob template that you wish to have a loot table.

Example Loot Table Template Code

  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE_RARITY+"0", Double(.045))
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE+"0","Brain Spike")
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE_RARITY+"1", Double(.075))
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE+"1","Shiny Plate Bracers")
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE_RARITY+"2", Double(.10))
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE+"2","Shiny Plate Helmet")
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE_RARITY+"3", Double(.10))
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE+"3","Axe o Cutting")
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE_RARITY+"4", Double(.30))
  mobOrcTMPL.put(InventoryClient.NAMESPACE, MarsInventoryClient.INV_TABLE+"4","Orc Spear")

The fact that the rarities are listed in increasing order does not really affect the code, as long as the total is equal to 1.0 (or less is fine). In this case since the mob has only 62% of its loot table defined, the other 38% of the time the mob spawns it will drop nothing (which is what we desired).


The Java Server Code

I probably could have done this as a server extension in python, however I am much more familiar with Java, and Java will obviously perform faster, and seeing as depending on the world size and the number of mobs you are spawning this code could be run fairly frequently faster = better.

First things first, we need to add a new class to handle the loot table.

Code for the LootTableEntry Class

  // you can replace this with multiverse.mars.objects
  // main thing is just make sure it matches the directory you place it in under the source.
  package com.andy.objects; 
  
  public class LootTableEntry {
     private String entryItems;
     private double entryRarity;
  
     public LootTableEntry(double rarity, String items){
        this.entryItems = items;
        this.entryRarity = rarity;
     }
  
     public double getEntryRarity(){
        return this.entryRarity;
     }
  
     public String getEntryItems(){
        return this.entryItems;
     }
  }

Additional Code for MarsInventoryPlugin

Find the following method

  /**
   * returns the bag, or null on failure
   */
  public Bag createInvSubObj(Long mobOid, Template template,
     GenerateSubObjectMessage msg) throws MVException, IOException {
        Map<String, Object> props = template
           .getSubMap(InventoryClient.NAMESPACE);
        if (props == null) {
           Log.warn("createInvSubObj: no props in ns "
                 + InventoryClient.NAMESPACE);
           return null;
        }
        
        // create root bag
        Log.debug("createInvSubObj: creating root bag, playeroid=" + mobOid);
        Bag rootBag = createRootBag(mobOid, 5);
        if (rootBag == null) {
           return null;
        }
        
        // copy properties from template to object
        for (Map.Entry<String, Object> entry : props.entrySet()) {
           String key = entry.getKey();
           Object value = entry.getValue();
           if (!key.startsWith(":")) {
               rootBag.setProperty(key, value);
           }
        }
        
        // create 5 sub bags
        for (int subBagNum = 0; subBagNum < 5; subBagNum++) {
           Log.debug("createInvSubObj: creating sub bag, moboid=" + mobOid
               + ", rootbag=" + rootBag + ", bag pos=" + subBagNum);
           Bag subBag = createSubBag(rootBag, subBagNum, 16);
           if (subBag == null) {
               return null;
           }
        }
        
       // register the entity
       getSubObjectManager().register(mobOid, InventoryClient.NAMESPACE,rootBag);

       /************************************************/        
       /*************** ADD NEW CODE HERE **************/
       /************************************************/ 
       // send a response message
       sendSubObjectResponse(msg, rootBag.getOid(),
          WorldManagerClient.NAMESPACE, new CreateInventoryHook(mobOid,
          invItems));
       return rootBag;
  }

And add the following code to it

        String invItems = (String) props.get(InventoryClient.TEMPL_ITEMS);
        // check to see if a loot table is defined.
        
        if(props.containsKey(MarsInventoryClient.INV_TABLE_RARITY+"0")){
           // yes we are defining a loot table.
           ArrayList<LootTableEntry> lootTable = new ArrayList<LootTableEntry>();
           int tableId = 0;
           double totalPercentage = 0.0;
           String tableItems = null;
           Double percentage = null;
           LootTableEntry entry = null;
           while(props.containsKey(MarsInventoryClient.INV_TABLE_RARITY+tableId)){
              if(props.containsKey(MarsInventoryClient.INV_TABLE+tableId)){
                  tableItems = (String) props.get(MarsInventoryClient.INV_TABLE+tableId);
                  percentage = (Double) props.get(MarsInventoryClient.INV_TABLE_RARITY+tableId);
                  entry = new LootTableEntry(percentage+totalPercentage,tableItems);
                  lootTable.add(entry);
                  totalPercentage += percentage;
              } else {
                  log.error("Rarity Is defined but no loot table. for ID->"+tableId);
                  throw(new MVException("Rarity Is defined but no loot table."));
              }
              tableId++;
           }
           
           if(lootTable.size() > 0){
              double roll = Math.random();
              for(int i=0; i<lootTable.size(); i++){
                 if(roll < lootTable.get(i).getEntryRarity()){
                    invItems = lootTable.get(i).getEntryItems();
                    break;
                 }
              }
           }
           	
       }

Code for MarsInventoryClient

And were almost done...

Add this to the bottom of MarsInventoryClient

  public static final String INV_TABLE = ":inv_loot_table";
  public static final String INV_TABLE_RARITY = ":inv_loot_rarity";

And now you can enjoy your game with the added bonus of LootTables :).


Smittydks 00:34, 22 November 2007 (PST) Help, Suggestions, Etc, feel free to pm (smittydks) me on the boards.

Personal tools