package electroblob.wizardry.registry; import com.google.common.collect.Lists; import electroblob.wizardry.Wizardry; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.entity.EntityMeteor; import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.construct.*; import electroblob.wizardry.entity.living.*; import electroblob.wizardry.entity.projectile.*; import electroblob.wizardry.loot.RandomSpell; import electroblob.wizardry.loot.WizardSpell; import electroblob.wizardry.tileentity.*; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureType; import net.minecraft.init.Biomes; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.ResourceLocation; import net.minecraft.world.biome.Biome; import net.minecraft.world.storage.loot.LootTableList; import net.minecraft.world.storage.loot.functions.LootFunctionManager; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.EntityRegistry; import net.minecraftforge.fml.common.registry.ForgeRegistries; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.ShapelessOreRecipe; import net.minecraftforge.registries.IForgeRegistry; import java.util.List; /** * Class responsible for registering all the things that don't have (or need) instances: entities, loot tables, recipes, * etc. * * @author Electroblob * @since Wizardry 1.0 */ @Mod.EventBusSubscriber public final class WizardryRegistry { /** Called from the preInit method in the main mod class to register the custom dungeon loot. */ public static void registerLoot(){ /* Loot tables work as follows: Minecraft goes through each pool in turn. For each pool, it does a certain * number of rolls, which can either be set to always be one number or a random number from a range. Each roll, * it generates one stack of a single random entry in that pool, weighted according to the weights of the * entries. Functions allow properties of that stack (stack size, damage, nbt) to be set, and even allow it to * be replaced dynamically with a completely different item (though there's very little point in doing that as * it could be achieved just as easily with more entries, which makes me think it would be bad practice). You * can also use conditions to control whether an entry or pool is used at all, which is mostly for mob drops * under specific conditions, but one of them is simply a random chance, meaning you could use it to make a pool * that only gets rolled sometimes. All in all, this can get rather confusing, because stackable items can have * 5 stages of randomness applied to them at once: a random chance for the pool, a random number of rolls for * the pool, the weighted random chance of choosing that particular entry, a random chance for that entry, and a * random stack size, and that's before you take functions into account. * * ...oh, and entries can be entire loot tables in themselves, allowing for potentially infinite levels of * randomness. Yeah. */ // Always registers the loot tables, but only injects the additions into vanilla if the appropriate option is // enabled in the config (see WizardryEventHandler). LootFunctionManager.registerFunction(new RandomSpell.Serializer()); LootFunctionManager.registerFunction(new WizardSpell.Serializer()); LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/wizard_tower")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "chests/dungeon_additions")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/novice_wands")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wizard_armour")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/arcane_tomes")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "subsets/wand_upgrades")); LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/evil_wizard")); // TODO: At the moment this is not used anywhere because I can't find a way to add it to all mobs. // LootTableList.register(new ResourceLocation(Wizardry.MODID, "entities/mob_additions")); } /** Called from the preInit method in the main mod class to register all the tile entities. */ public static void registerTileEntities(){ GameRegistry.registerTileEntity(TileEntityArcaneWorkbench.class, Wizardry.MODID + "ArcaneWorkbenchTileEntity"); GameRegistry.registerTileEntity(TileEntityStatue.class, Wizardry.MODID + "PetrifiedStoneTileEntity"); GameRegistry.registerTileEntity(TileEntityMagicLight.class, Wizardry.MODID + "MagicLightTileEntity"); GameRegistry.registerTileEntity(TileEntityTimer.class, Wizardry.MODID + "TimerTileEntity"); GameRegistry.registerTileEntity(TileEntityPlayerSave.class, Wizardry.MODID + "TileEntityPlayerSave"); } /** Not actually the frequency at all; smaller numbers are more frequent. Vanilla uses 3 I think. */ private static final int LIVING_UPDATE_INTERVAL = 3; /** Not actually the frequency at all; smaller numbers are more frequent. */ private static final int PROJECTILE_UPDATE_INTERVAL = 10; /** Called from the preInit method in the main mod class to register all the entities. */ public static void registerEntities(){ int id = 0; // Incrementable index for the mod specific entity id. registerEntity(EntityZombieMinion.class, "zombie_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityMagicMissile.class, "magic_missile", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); // TODO: This should be a particle registerEntity(EntityArc.class, "arc", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntitySkeletonMinion.class, "skeleton_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntitySparkBomb.class, "spark_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntitySpiritWolf.class, "spirit_wolf", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityIceShard.class, "ice_shard", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityBlazeMinion.class, "blaze_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityIceWraith.class, "ice_wraith", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityLightningWraith.class, "lightning_wraith", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityBlackHole.class, "black_hole", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityShield.class, "shield", id++, 128, 1, true); registerEntity(EntityMeteor.class, "meteor", id++, 128, 5, true); registerEntity(EntityBlizzard.class, "blizzard", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntityAndEgg(EntityWizard.class, "wizard", id++, 128, LIVING_UPDATE_INTERVAL, true, 0x19295e, 0xee9312); registerEntity(EntityBubble.class, "bubble", id++, 128, 3, false); registerEntity(EntityTornado.class, "tornado", id++, 128, 1, false); registerEntity(EntityHammer.class, "lightning_hammer", id++, 128, 1, true); registerEntity(EntityFirebomb.class, "firebomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityForceOrb.class, "force_orb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityArrowRain.class, "arrow_rain", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntitySpark.class, "spark", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityShadowWraith.class, "shadow_wraith", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityDarknessOrb.class, "darkness_orb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntitySpiderMinion.class, "spider_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityHealAura.class, "healing_aura", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityFireSigil.class, "fire_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityFrostSigil.class, "frost_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityLightningSigil.class, "lightning_sigil", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityLightningArrow.class, "lightning_arrow", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityFirebolt.class, "firebolt", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityPoisonBomb.class, "poison_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityIceCharge.class, "ice_charge", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityForceArrow.class, "force_arrow", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityDart.class, "dart", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityMagicSlime.class, "magic_slime", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityForcefield.class, "forcefield", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityFireRing.class, "ring_of_fire", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityLightningDisc.class, "lightning_disc", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityThunderbolt.class, "thunderbolt", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityIceGiant.class, "ice_giant", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntitySpiritHorse.class, "spirit_horse", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityPhoenix.class, "phoenix", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntitySilverfishMinion.class, "silverfish_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityDecay.class, "decay", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityStormElemental.class, "storm_elemental", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityEarthquake.class, "earthquake", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityIceLance.class, "ice_lance", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntity(EntityHailstorm.class, "hailstorm", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntitySmokeBomb.class, "smoke_bomb", id++, 128, PROJECTILE_UPDATE_INTERVAL, true); registerEntityAndEgg(EntityEvilWizard.class, "evil_wizard", id++, 128, LIVING_UPDATE_INTERVAL, true, 0x290404, 0xee9312); registerEntity(EntityDecoy.class, "decoy", id++, 128, LIVING_UPDATE_INTERVAL, true); registerEntity(EntityIceSpike.class, "ice_spike", id++, 128, 1, true); // TODO: This should be a particle. registerEntity(EntityLightningPulse.class, "lightning_pulse", id++, 128, PROJECTILE_UPDATE_INTERVAL, false); registerEntity(EntityWitherSkeletonMinion.class, "wither_skeleton_minion", id++, 128, LIVING_UPDATE_INTERVAL, true); // TODO: May need fixing List biomes = Lists.newArrayList(); for (Biome biome : ForgeRegistries.BIOMES.getValuesCollection()) { biomes.add(biome); } biomes.remove(Biomes.MUSHROOM_ISLAND); biomes.remove(Biomes.MUSHROOM_ISLAND_SHORE); // For reference: 5, 1, 1 are the parameters for the witch in vanilla. EntityRegistry.addSpawn(EntityEvilWizard.class, 3, 1, 1, EnumCreatureType.MONSTER, biomes.toArray(new Biome[biomes.size()])); } /** Private helper method for registering entities; keeps things neater. For some reason, Forge 1.11.2 wants a * ResourceLocation and a string name... probably because it's transitioning to the registry system. */ private static void registerEntity(Class entityClass, String name, int id, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates){ ResourceLocation registryName = new ResourceLocation(Wizardry.MODID, name); EntityRegistry.registerModEntity(registryName, entityClass, registryName.toString(), id, Wizardry.instance, trackingRange, updateFrequency, sendsVelocityUpdates); } /** Private helper method for registering entities with eggs; keeps things neater. For some reason, Forge 1.11.2 * wants a ResourceLocation and a string name... probably because it's transitioning to the registry system. */ private static void registerEntityAndEgg(Class entityClass, String name, int id, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates, int eggColour, int spotColour){ ResourceLocation registryName = new ResourceLocation(Wizardry.MODID, name); EntityRegistry.registerModEntity(registryName, entityClass, registryName.toString(), id, Wizardry.instance, trackingRange, updateFrequency, sendsVelocityUpdates); EntityRegistry.registerEgg(registryName, eggColour, spotColour); } /** Now only deals with the dynamic crafting recipes and the smelting recipes. */ @SubscribeEvent public static void registerRecipes(RegistryEvent.Register event){ IForgeRegistry registry = event.getRegistry(); FurnaceRecipes.instance().addSmeltingRecipeForBlock(WizardryBlocks.crystal_ore, new ItemStack(WizardryItems.magic_crystal), 0.5f); // Mana flask recipes ItemStack manaFlaskStack = new ItemStack(WizardryItems.mana_flask); ItemStack miscWandStack; for(Element element : Element.values()){ for(Tier tier : Tier.values()){ miscWandStack = new ItemStack(WizardryUtilities.getWand(tier, element), 1, OreDictionary.WILDCARD_VALUE); registry.register(new ShapelessOreRecipe(null, miscWandStack, miscWandStack, manaFlaskStack){ @Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/flask_wand_" + element.getUnlocalisedName() + "_" + tier.getUnlocalisedName()))); } } ItemStack miscArmourStack; for(Element element : Element.values()){ for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){ miscArmourStack = new ItemStack(WizardryUtilities.getArmour(element, slot), 1, OreDictionary.WILDCARD_VALUE); registry.register(new ShapelessOreRecipe(null, miscArmourStack, miscArmourStack, manaFlaskStack){ @Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book }.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/flask_armour_" + element.getUnlocalisedName() + "_" + slot.getName()))); } } } }