Merge pull request #74 from SenseiKiwi/master

Improved Dungeon Loot and Selection
This commit is contained in:
StevenRS11 2013-08-24 10:45:39 -07:00
commit 928b7d4cba
4 changed files with 92 additions and 31 deletions

View file

@ -4,7 +4,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraftforge.common.ChestGenHooks;
@ -33,6 +36,8 @@ public class DDLoot {
private static final int RARE_LOOT_WEIGHT = 1; //Same weight as music discs, golden apple
private static final int DUNGEON_CHEST_WEIGHT_INFLATION = 10; // (weight of iron ingots in dungeon) / (weight of iron ingots in other chests)
private DDLoot() { }
public static void registerInfo()
{
DDProperties properties = DDProperties.instance();
@ -156,4 +161,48 @@ public class DDLoot {
//System.out.println(item.theItemId.getDisplayName() + "\t" + item.itemWeight);
}
}
public static void generateChestContents(ChestGenHooks chestInfo, IInventory inventory, Random random)
{
//This is a custom version of net.minecraft.util.WeightedRandomChestContent.generateChestContents()
//It's designed to avoid the following bugs in MC 1.5:
//1. The randomized filling algorithm will sometimes overwrite item stacks with other stacks
//2. If multiple enchanted books appear, then they will have the same enchantment
//The prime number below is used for choosing chest slots in a seemingly-random pattern. Its value
//was selected specifically to achieve a spread-out distribution for chests with up to 104 slots.
//Choosing a prime number ensures that our increments are relatively-prime to the chest size, which
//means we'll cover all the slots before repeating any. This is mathematically guaranteed.
final int primeOffset = 239333;
int count = chestInfo.getCount(random);
int size = inventory.getSizeInventory();
WeightedRandomChestContent[] content = chestInfo.getItems(random);
for (int k = 0; k < count; k++)
{
WeightedRandomChestContent selection = (WeightedRandomChestContent)WeightedRandom.getRandomItem(random, content);
//Call getChestGenBase() to make sure we generate a different enchantment for books.
//Don't just use a condition to check if the item is an instance of ItemEnchantedBook because
//we don't know if other mods might add items that also need to be regenerated.
selection = selection.theItemId.getItem().getChestGenBase(chestInfo, random, selection);
ItemStack[] stacks = ChestGenHooks.generateStacks(random, selection.theItemId, selection.theMinimumChanceToGenerateItem, selection.theMaximumChanceToGenerateItem);
for (ItemStack item : stacks)
{
int limit = size;
int index = random.nextInt(size);
while (limit > 0 && inventory.getStackInSlot(index) != null)
{
limit--;
index = (index + primeOffset) % size;
}
inventory.setInventorySlotContents(index, item);
}
}
}
}

View file

@ -42,7 +42,7 @@ public class SchematicLoader
if (dimList.get(destDimID).dungeonGenerator == null)
{
//TODO: We should centralize RNG initialization and world-seed modifiers for each specific application.
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ computeDestinationHash(link);
final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ calculateDestinationSeed(link);
final Random random = new Random(localSeed);
dungeonHelper.generateDungeonLink(link, dungeonHelper.getDimDungeonPack(originDimID), random);
@ -155,43 +155,50 @@ public class SchematicLoader
return dungeon;
}
private static long computeDestinationHash(LinkData link)
private static long calculateDestinationSeed(LinkData link)
{
//Time for some witchcraft.
//The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D.
//Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence
//Use 8 bits from Y and 24 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means
//Use 8 bits from Y and 16 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means
//even if you aligned two doors perfectly between two pockets, it's unlikely they would lead to the same dungeon.
//We map bits in reverse order to produce more varied RNG output for nearly-identical points. The reason is
//that Java's Random outputs the 32 MSBs of its internal state to produce its output. If the differences
//between two seeds are small (i.e. in the LSBs), then they will tend to produce similar random outputs anyway!
//Only bother to assign the 48 least-significant bits since Random only takes those bits from its seed.
//NOTE: The casts to long are necessary to get the right results from the bit shifts!!!
int bit;
int index;
long hash;
int w = link.destDimID;
int x = link.destXCoord;
int y = link.destYCoord;
int z = link.destZCoord;
final int w = link.destDimID;
final int x = link.destXCoord;
final int y = link.destYCoord;
final int z = link.destZCoord;
hash = 0;
index = 0;
index = 48;
for (bit = 0; bit < 8; bit++)
{
hash |= ((w >> bit) & 1) << index;
index++;
hash |= ((x >> bit) & 1) << index;
index++;
hash |= ((y >> bit) & 1) << index;
index++;
hash |= ((z >> bit) & 1) << index;
index++;
hash |= (long) ((w >> bit) & 1) << index;
index--;
hash |= (long) ((x >> bit) & 1) << index;
index--;
hash |= (long) ((y >> bit) & 1) << index;
index--;
hash |= (long) ((z >> bit) & 1) << index;
index--;
}
for (; bit < 24; bit++)
for (; bit < 16; bit++)
{
hash |= ((x >> bit) & 1) << index;
index++;
hash |= ((z >> bit) & 1) << index;
index++;
hash |= (long) ((x >> bit) & 1) << index;
index--;
hash |= (long) ((z >> bit) & 1) << index;
index--;
}
return hash;
}
}

View file

@ -10,9 +10,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.world.World;
import net.minecraftforge.common.ChestGenHooks;
import StevenDimDoors.mod_pocketDim.DDLoot;
import StevenDimDoors.mod_pocketDim.schematic.WorldOperation;
@ -42,8 +40,7 @@ public class FillContainersOperation extends WorldOperation
TileEntityChest chest = (TileEntityChest) tileEntity;
if (isInventoryEmpty(chest))
{
ChestGenHooks info = DDLoot.DungeonChestInfo;
WeightedRandomChestContent.generateChestContents(random, info.getItems(random), chest, info.getCount(random));
DDLoot.generateChestContents(DDLoot.DungeonChestInfo, chest, random);
}
}

View file

@ -22,14 +22,22 @@ Exit -> DeadEnd Exit
DeadEnd -> DeadEnd Exit
? ? ? ? ? ? ? ? -> Trap#20 SimpleHall#40 ComplexHall#10 Exit#20 DeadEnd#10
? ? ? ? ? ? ? ? ? -> DeadEnd#10 Exit#11 SimpleHall#24 ComplexHall#16 Trap#23 Maze#11
? ? ? ? -> Trap#18 SimpleHall#40 ComplexHall#10 Exit#18 DeadEnd#10 Hub#4
? ? ? ? ? ? ? ? -> DeadEnd#9 Exit#10 SimpleHall#24 ComplexHall#16 Trap#23 Maze#11 Hub#6
? ? ? -> ComplexHall Hub Trap SimpleHall Maze
? ? ? ? ? ? ? -> DeadEnd#8 Exit#9 SimpleHall#25 ComplexHall#17 Trap#23 Maze#11 Hub#7
? ? -> ComplexHall Hub Trap SimpleHall Maze
? ? ? ? ? ? -> DeadEnd#7 Exit#8 SimpleHall#26 ComplexHall#17 Trap#23 Maze#11 Hub#8
? -> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10
? ? ? ? ? -> DeadEnd#6 Exit#6 SimpleHall#27 ComplexHall#18 Trap#23 Maze#11 Hub#9
-> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10
? ? ? ? -> DeadEnd#5 Exit#5 SimpleHall#28 ComplexHall#18 Trap#23 Maze#11 Hub#10
? ? ? -> DeadEnd#3 Exit#3 SimpleHall#29 ComplexHall#19 Trap#23 Maze#11 Hub#11
? ? -> SimpleHall#9 ComplexHall#8 Trap#17 Maze#23 Hub#44
? -> SimpleHall#9 ComplexHall#8 Trap#17 Maze#23 Hub#44
-> SimpleHall#2 ComplexHall#54 Trap#2 Maze#2 Hub#41