Loot tables

Anyone have any sample code or pseudo-code on how to implement these (nicely?) in Java.

I currently roll a rand(10) that feeds a 10 case switch statement to test stuff, but now I need concept of rarity…

I’ve googled a bit but found nothing that resembled a lookup table structure (which is what I thought loot-tables were supposed to be based on??)

EDIT: Example usage (different class, but the same principle) - http://www.java-gaming.org/topics/calculating-probabilities-is-this-the-right-way/33201/msg/311483/view.html#msg311483

Have you seen http://www.codeproject.com/Articles/420046/Loot-Tables-Random-Maps-and-Monsters-Part-I in your search?
I translated it into Java but I can’t access the code right now.

Have you seen this page: http://gamedevelopment.tutsplus.com/tutorials/how-to-code-monster-loot-drops--cms-20449

Kids…let this be an example to you. Math: It works bitches.

Excellent!

I’ll try some of those after work. Thanks guys!

big grin

I probably should have pointed to this as well: https://github.com/roquendm/JGO-Grabbag/blob/master/src/roquen/math/rng/discrete/RandomSelect.java

Slower evaluation, smaller data-tables and already returns an object instead of an integer. I can’t see how slower would be a problem for the usage.

What I did once with a loot table was using a enum class of the items

And within that enum class I added an array of items

Like this example:


public enum Item {
// item name, item sprite, item option/tag
	NULL("NULL",1,Assets.null(), "null"),
	HEALTH_POT("Health Potion",2,Assets.getHealthPotion(), "use"),
	STAMINA_POT("Stamina Potion",3,Assets.getStaminaPotion(), "use"),
	HELM_RED("Red Helm",4,Assets.getHelm_red(), "wear"),
	BODY_RED("Red Body",5,Assets.getBody_red(), "wear"),
	LEGS_RED("Red Legs",6,Assets.getLegs_red(), "wear"),
	BOOTS_RED("Red Boots",7,Assets.getBoots_red(), "wear");
	
	private int itemID;
	private BufferedImage itemImage;
	private String itemName;
	private String tag;
	
	public Item[] itemPack_01 = {
		Item.HEALTH_POT, Item.BODY_RED, Item.HELM_RED, Item.STAMINA_POT, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL
	};
	
	public Item[] itemPack_02 = {
		Item.HEALTH_POT, Item.BOOTS_RED, Item.LEGS_RED, Item.STAMINA_POT, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL, Item.NULL
	};
	
	private Item(String itemName,int itemID, BufferedImage itemImage, String tag) {
		this.itemName = itemName;
		this.itemID = itemID;
		this.itemImage = itemImage;
		this.tag = tag;
	}
	
	public int getItemID() {
		return itemID;
	}
	public BufferedImage getItemImage() {
		return itemImage;
	}
	public String getItemName() {
		return itemName;
	}
	public String getTag() {
		return tag;
	}
}

When ever looting a chest killing an enemy, or anything that gives items, you can get a random item from the
length of the array you choosed. like this:


public Item getItem() {
		Item dropItem;
		int l = items.length;
		int i = (int)(Math.random()*l);
		if(i > l){ // just in case
			dropItem = Item.NULL;
		} else {
			dropItem = items[i];
		}
		return dropItem;
	}

I based this on a old Runescape private server loot system.

But I would recommend the post of roquen, because it is easier to make guides of how much % to get an item etc,
and to edit and difficulty’s rates.
But if your game is not that big, and you want a fast and easy way, I would recommend this.

How about this?

EDIT: Updated with cleaner code.


public class LootTable {

    //map of item to relative frequency; rarest = 1
    private static final Map<String, Integer> lootables = new HashMap<String, Integer>() {{
        put("Gold", 1);
        put("Silver", 10);
        put("Copper", 100);
        put("Sapphire", 3);
        put("Chocolate", 6);
        put("BookOfPoems", 9);
    }};
    private static final TreeMap<Integer, String> lootTable = new TreeMap<>();
    private static final TreeMap<String, Integer> lootCount = new TreeMap<>();
    private static final Random R = new Random();


    public static void main(String[] args) {
        int range = 0;
        for (Map.Entry<String, Integer> entry : lootables.entrySet()) {
            range += entry.getValue();
            lootTable.put(range, entry.getKey());
        }
        for (int treasureChests = 0; treasureChests < 10_000_000; treasureChests++) {
            int i = R.nextInt(range) + 1;
            String loot = lootTable.ceilingEntry(i).getValue();
            lootCount.put(loot, lootCount.getOrDefault(loot, 0) + 1);
        }
        for (Map.Entry<String,Integer> entry : lootCount.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue() * 1f / lootCount.get("Gold"));
        }
    }
}

Running it I get:

BookOfPoems = 9.0155945 Chocolate = 6.0101285 Copper = 100.45237 Gold = 1.0 Sapphire = 3.0099344 Silver = 10.033909

Roquen, are you saying there is something specifically wrong with this solution? If so, please expand your point.

Math: it works.

You’re performing a linear time method to solve a problem that’s constant time. Also it’s walking (and requires) a fair amount of memory and boxing/unboxing values along the way. Does it matter? Very unlikely.

You can’t include the time to build the loot table - that is one-off on game load. The TreeMap.ceilingEntry() lookup should be a binary search so O(log n). If boxing is an issue a primitive map can be used, but that is not necessary in this context as you note.

Oh yeah, tree map, so you’re correct O(ln(n)). Still bigger than O(1) in time and structure is bigger is space. And like I said…not that any of this should matter.