diff --git a/changelog.txt b/changelog.txt index 38cbd0f5..27fe43e3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,9 @@ Version 3.0.1 - Added a few WIP items that cannot be used yet - they're part of the D*$)@ D*#@(@* system that I'm adding for Tier 4. - Added the API - It's still in flux, so expect it to change very soon! - Probably forgot something important. +- Fixed a crash for the Lava Crystal that made it blow up the Client if used on a server. No, that was not the intended purpose! +- Added the Ritual Tinkerer for Rituals. +- Added the "Tome of Peritia" again - stores EXP. ------------------------------------------------------ diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index ead33962..d94080a9 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -56,7 +56,7 @@ e6d9cf699667aaa47efff37b2b033895dee29c15 assets/bloodmagic/blockstates/waterritu 42f26f715bddd16c069f9b51e3767b36477c8908 assets/bloodmagic/blockstates/woodtilepath.json 3c6ce233dae6c1307d9016406c324bbe844b4e1e assets/bloodmagic/blockstates/wornstonebrickpath.json d59655f12d1724b73b77c373fb6864fcff69db12 assets/bloodmagic/blockstates/wornstonetilepath.json -b5dd19f496ee32e0301a21f38255c0fb3f2fae7f assets/bloodmagic/lang/en_us.json +6db439502b9bb27666e8297b8e3b7a63f78dc967 assets/bloodmagic/lang/en_us.json 34445195b9f2459475cde53454bc8e37d32865d7 assets/bloodmagic/models/block/accelerationrune.json bcdbccc49d4509571be6988762ab87126275a4c8 assets/bloodmagic/models/block/airritualstone.json adf6c0b1e25451609486dc8c8cfbd9cf0f8c67f4 assets/bloodmagic/models/block/alchemicalreactionchamber.json @@ -248,6 +248,7 @@ f3b763d6edc3c75655797481f05e02d409f481d9 assets/bloodmagic/models/item/dungeon_p 98ee75786f9d0ab2a8c0835896d07d18df77de0f assets/bloodmagic/models/item/earthscribetool.json cdbaaf8662f2e855a34a66f28e49403c4ea9a45e assets/bloodmagic/models/item/ethereal_mimic.json 4c39378f6c14dc243a7d52564e5a21df94683415 assets/bloodmagic/models/item/etherealslate.json +823b5cc34bf73811058f47ff73d760a8c0b2b1ea assets/bloodmagic/models/item/experiencebook.json 6ccd9f4e27f43b7f30217e73e0cdfad3bc826b1e assets/bloodmagic/models/item/explosivepowder.json c36bde4f98c0aeb3bf0f369ad3bc067e5f0dc916 assets/bloodmagic/models/item/fireritualstone.json b5708a8cc7259fd36ffeabd155ea085b9fdef0fd assets/bloodmagic/models/item/firescribetool.json @@ -402,6 +403,7 @@ e897d6f91e2a0bd12b0da0a50e5c897294989e7c data/bloodmagic/advancements/recipes/bl 7ca400d1141ff4be1b529cd060950b42cf3b9bfb data/bloodmagic/advancements/recipes/bloodmagictab/blood_rune_speed.json 764e54fdaa24f87cceb815990bbbd2e2cd87f205 data/bloodmagic/advancements/recipes/bloodmagictab/bloodstonebrick.json 2e7ec285e758b06c2bd7d9fd93eedd96f511fa49 data/bloodmagic/advancements/recipes/bloodmagictab/corrupted_dust.json +f92c8a88a2c0ca63510d170c33f5eb2d1aee25ec data/bloodmagic/advancements/recipes/bloodmagictab/experience_tome.json 1b1dab3143eae33e25c4a14c011adec72768c9b5 data/bloodmagic/advancements/recipes/bloodmagictab/hellforged_block.json a6f012d0584d36d9b7dd0ec4f9e4cbd2a3ff1146 data/bloodmagic/advancements/recipes/bloodmagictab/incense_altar.json 4c24af93a64071aadc0308b27bcbc44572e5ccfc data/bloodmagic/advancements/recipes/bloodmagictab/largebloodstonebrick.json @@ -575,6 +577,7 @@ b63d77c3762f86d4a91f62e192c3e9b26e3b52ca data/bloodmagic/recipes/blood_rune_sacr e2bcf2a6f951fbcef45554ec90ba28d14e261d18 data/bloodmagic/recipes/blood_rune_speed.json eeb5e64b8bc90adc2554dde88b8792b92ad7c8cc data/bloodmagic/recipes/bloodstonebrick.json 68e9201ef0d0051618a73434b35791a208bacde1 data/bloodmagic/recipes/corrupted_dust.json +ab11cf6806dab2a2d1cda2f7fde9cd2ecd9cdf9f data/bloodmagic/recipes/experience_tome.json 84aeee900c15d94f1940e72c8f331755d0a97b11 data/bloodmagic/recipes/hellforged_block.json 9a5749465020b32b0147b3367784ce31a0d3b54b data/bloodmagic/recipes/incense_altar.json 63bca28ba5eebb9c488c819bcb117595eadb877d data/bloodmagic/recipes/largebloodstonebrick.json diff --git a/src/generated/resources/assets/bloodmagic/lang/en_us.json b/src/generated/resources/assets/bloodmagic/lang/en_us.json index f6180327..75fa0670 100644 --- a/src/generated/resources/assets/bloodmagic/lang/en_us.json +++ b/src/generated/resources/assets/bloodmagic/lang/en_us.json @@ -94,6 +94,7 @@ "item.bloodmagic.duskscribetool": "Inscription Tool: Dusk", "item.bloodmagic.earthscribetool": "Inscription Tool: Earth", "item.bloodmagic.etherealslate": "Ethereal Slate", + "item.bloodmagic.experiencebook": "Tome of Peritia", "item.bloodmagic.explosivepowder": "Explosive Powder", "item.bloodmagic.firescribetool": "Inscription Tool: Fire", "item.bloodmagic.fragment_netherite_scrap": "Ancient Debris Fragment", @@ -352,6 +353,9 @@ "tooltip.bloodmagic.diviner.fireRune": "Fire Runes: %d", "tooltip.bloodmagic.diviner.totalRune": "Total Runes: %d", "tooltip.bloodmagic.diviner.waterRune": "Water Runes: %d", + "tooltip.bloodmagic.experienceTome": "A book used to store experience", + "tooltip.bloodmagic.experienceTome.exp": "Exp: %0.3f", + "tooltip.bloodmagic.experienceTome.expLevel": "Level: %d", "tooltip.bloodmagic.extraInfo": "&9-Hold shift for more info-", "tooltip.bloodmagic.holdShiftForInfo": "Press shift for extra info", "tooltip.bloodmagic.inscriber.desc": "The writing is on the wall...", diff --git a/src/generated/resources/assets/bloodmagic/models/item/experiencebook.json b/src/generated/resources/assets/bloodmagic/models/item/experiencebook.json new file mode 100644 index 00000000..5be169c0 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/experiencebook.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/experiencebook" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/advancements/recipes/bloodmagictab/experience_tome.json b/src/generated/resources/data/bloodmagic/advancements/recipes/bloodmagictab/experience_tome.json new file mode 100644 index 00000000..16e94029 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/advancements/recipes/bloodmagictab/experience_tome.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "bloodmagic:experience_tome" + ] + }, + "criteria": { + "has_magician_orb": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "bloodmagic:magicianbloodorb" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "bloodmagic:experience_tome" + } + } + }, + "requirements": [ + [ + "has_magician_orb", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/recipes/experience_tome.json b/src/generated/resources/data/bloodmagic/recipes/experience_tome.json new file mode 100644 index 00000000..633dbd55 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/recipes/experience_tome.json @@ -0,0 +1,32 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "ses", + "lbl", + "gog" + ], + "key": { + "b": { + "item": "minecraft:enchanted_book" + }, + "s": { + "tag": "forge:string" + }, + "e": { + "tag": "forge:storage_blocks/lapis" + }, + "g": { + "tag": "forge:ingots/gold" + }, + "l": { + "item": "bloodmagic:infusedslate" + }, + "o": { + "type": "bloodmagic:bloodorb", + "orb_tier": 3 + } + }, + "result": { + "item": "bloodmagic:experiencebook" + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBaseRecipes.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBaseRecipes.java index e86c55ad..47ff3943 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBaseRecipes.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBaseRecipes.java @@ -94,6 +94,7 @@ public class GeneratorBaseRecipes extends BaseRecipeProvider ShapedRecipeBuilder.shapedRecipe(BloodMagicItems.RITUAL_READER.get()).key('s', BloodMagicItems.DEMONIC_SLATE.get()).key('g', Tags.Items.GLASS).key('i', Tags.Items.INGOTS_GOLD).key('o', IngredientBloodOrb.fromOrb(BloodMagicItems.ORB_MASTER.get())).patternLine("gog").patternLine("isi").patternLine(" s ").addCriterion("has_master_orb", hasItem(BloodMagicItems.MASTER_BLOOD_ORB.get())).build(consumer, BloodMagic.rl("ritual_reader")); + ShapedRecipeBuilder.shapedRecipe(BloodMagicItems.EXPERIENCE_TOME.get()).key('b', Items.ENCHANTED_BOOK).key('s', Tags.Items.STRING).key('e', Tags.Items.STORAGE_BLOCKS_LAPIS).key('g', Tags.Items.INGOTS_GOLD).key('l', BloodMagicItems.IMBUED_SLATE.get()).key('o', IngredientBloodOrb.fromOrb(BloodMagicItems.ORB_MAGICIAN.get())).patternLine("ses").patternLine("lbl").patternLine("gog").addCriterion("has_magician_orb", hasItem(BloodMagicItems.MAGICIAN_BLOOD_ORB.get())).build(consumer, BloodMagic.rl("experience_tome")); // ShapedRecipeBuilder.shapedRecipe(BloodMagicBlocks.MIMIC.get()).key('b', itemIn) // ShapedRecipeBuilder.shapedRecipe(BloodMagicBlocks.SPEED_RUNE.get()).key('s', Items.GLASS).key('o', Ingredient.fromItems(Items.DIAMOND)).patternLine("sss").patternLine("sos").patternLine("sss").addCriterion("has_diamond", hasItem(Items.DIAMOND)).build(consumer, new ResourceLocation(BloodMagic.MODID, "speed_rune_from_standard")); // ShapedRecipeBuilder.shapedRecipe(BloodMagicBlocks.SPEED_RUNE.get()).key('s', Items.GLASS).key('o', IngredientBloodOrb.fromOrb(BloodMagicItems.ORB_WEAK.get())).patternLine("sss").patternLine("sos").patternLine("sss").addCriterion("has_diamond", hasItem(Items.DIAMOND)).build(consumer, new ResourceLocation(BloodMagic.MODID, "speed_rune_from_orb")); diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java index ca902874..eacefad8 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java @@ -109,6 +109,10 @@ public class GeneratorLanguage extends LanguageProvider add("itemGroup.bloodmagictab", "Blood Magic"); + add("tooltip.bloodmagic.experienceTome", "A book used to store experience"); + add("tooltip.bloodmagic.experienceTome.exp", "Exp: %0.3f"); + add("tooltip.bloodmagic.experienceTome.expLevel", "Level: %d"); + // Ritual info add("tooltip.bloodmagic.diviner.currentRitual", "Current Ritual: %s"); add("tooltip.bloodmagic.diviner.blankRune", "Blank Runes: %d"); @@ -454,6 +458,8 @@ public class GeneratorLanguage extends LanguageProvider addItem(BloodMagicItems.BASIC_CUTTING_FLUID, "Basic Cutting Fluid"); + addItem(BloodMagicItems.EXPERIENCE_TOME, "Tome of Peritia"); + // Alchemy Items addItem(BloodMagicItems.PLANT_OIL, "Plant Oil"); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java index 5cf691b6..e21d8959 100644 --- a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java +++ b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java @@ -128,6 +128,7 @@ public class BloodMagicItems public static final RegistryObject DAGGER_OF_SACRIFICE = BASICITEMS.register("daggerofsacrifice", () -> new ItemDaggerOfSacrifice()); public static final RegistryObject LAVA_CRYSTAL = BASICITEMS.register("lavacrystal", () -> new ItemLavaCrystal()); public static final RegistryObject WEAK_BLOOD_SHARD = BASICITEMS.register("weakbloodshard", () -> new ItemBase()); + public static final RegistryObject EXPERIENCE_TOME = BASICITEMS.register("experiencebook", () -> new ItemExperienceBook()); // Ritual stuffs public static final RegistryObject WEAK_ACTIVATION_CRYSTAL = BASICITEMS.register("activationcrystalweak", () -> new ItemActivationCrystal(ItemActivationCrystal.CrystalType.WEAK)); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemExperienceBook.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemExperienceBook.java new file mode 100644 index 00000000..9fc4f06d --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemExperienceBook.java @@ -0,0 +1,209 @@ +package wayoftime.bloodmagic.common.item; + +import java.util.List; + +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.util.BMLog; +import wayoftime.bloodmagic.util.helper.NBTHelper; + +public class ItemExperienceBook extends Item +{ + public ItemExperienceBook() + { + super(new Item.Properties().maxStackSize(1).group(BloodMagic.TAB)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public boolean hasEffect(ItemStack stack) + { + return true; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) + { + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.experienceTome")); + + if (!stack.hasTag()) + return; + + double storedExp = getStoredExperience(stack); + + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.experienceTome.exp", (int) storedExp)); + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.experienceTome.expLevel", (int) getLevelForExperience(storedExp))); + } + + @Override + public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) + { + ItemStack stack = player.getHeldItem(hand); + if (!world.isRemote) + { + if (player.isSneaking()) + absorbOneLevelExpFromPlayer(stack, player); + else + giveOneLevelExpToPlayer(stack, player); + } + + return new ActionResult<>(ActionResultType.SUCCESS, stack); + } + + public void giveOneLevelExpToPlayer(ItemStack stack, PlayerEntity player) + { + float progress = player.experience; + int expToNext = getExperienceForNextLevel(player.experienceLevel); + + int neededExp = (int) Math.ceil((1 - progress) * expToNext); + float containedExp = (float) getStoredExperience(stack); + + BMLog.DEBUG.info("Needed: " + neededExp + ", contained: " + containedExp + ", exp to next: " + expToNext); + + if (containedExp >= neededExp) + { + setStoredExperience(stack, containedExp - neededExp); + addPlayerXP(player, neededExp); + + if (player.experienceLevel % 5 == 0) + { + float f = player.experienceLevel > 30 ? 1.0F : (float) player.experienceLevel / 30.0F; + player.getEntityWorld().playSound(null, player.getPosX(), player.getPosY(), player.getPosZ(), SoundEvents.ENTITY_PLAYER_LEVELUP, player.getSoundCategory(), f * 0.75F, 1.0F); + } + } else + { + setStoredExperience(stack, 0); + addPlayerXP(player, (int) containedExp); + } + } + + public void absorbOneLevelExpFromPlayer(ItemStack stack, PlayerEntity player) + { + float progress = player.experience; + + if (progress > 0) + { + int expDeduction = (int) getExperienceAcquiredToNext(player); + if (expDeduction > 0) + { + addPlayerXP(player, -expDeduction); + addExperience(stack, expDeduction); + } + } else if (progress == 0 && player.experienceLevel > 0) + { + int expDeduction = getExperienceForNextLevel(player.experienceLevel - 1); + addPlayerXP(player, -expDeduction); + addExperience(stack, expDeduction); + } + } + + // Credits to Ender IO for some of the experience code, although now modified + // slightly for my convenience. + public static int getPlayerXP(PlayerEntity player) + { + return (int) (getExperienceForLevel(player.experienceLevel) + (player.experience * player.xpBarCap())); + } + + public static void addPlayerXP(PlayerEntity player, int amount) + { + int experience = Math.max(0, getPlayerXP(player) + amount); + player.experienceTotal = experience; + player.experienceLevel = getLevelForExperience(experience); + int expForLevel = getExperienceForLevel(player.experienceLevel); + player.experience = (float) (experience - expForLevel) / (float) player.xpBarCap(); + } + + public static void setStoredExperience(ItemStack stack, double exp) + { + NBTHelper.checkNBT(stack); + + CompoundNBT tag = stack.getTag(); + + tag.putDouble("experience", exp); + } + + public static double getStoredExperience(ItemStack stack) + { + NBTHelper.checkNBT(stack); + + CompoundNBT tag = stack.getTag(); + + return tag.getDouble("experience"); + } + + public static void addExperience(ItemStack stack, double exp) + { + setStoredExperience(stack, getStoredExperience(stack) + exp); + } + + public static int getExperienceForNextLevel(int currentLevel) + { + if (currentLevel < 16) + { + return 2 * currentLevel + 7; + } else if (currentLevel < 31) + { + return 5 * currentLevel - 38; + } else + { + return 9 * currentLevel - 158; + } + } + + // TODO: Change to calculation form. + public static int getExperienceForLevel(int level) + { + if (level >= 21863) + { + return Integer.MAX_VALUE; + } + if (level == 0) + { + return 0; + } + int res = 0; + for (int i = 0; i < level; i++) + { + res += getExperienceForNextLevel(i); + } + return res; + } + + public static double getExperienceAcquiredToNext(PlayerEntity player) + { + return player.experience * player.xpBarCap(); + } + + public static int getLevelForExperience(double exp) + { + if (exp <= 352) + { + return (int) Math.floor(solveParabola(1, 6, -exp)); + } else if (exp <= 1507) + { + return (int) Math.floor(solveParabola(2.5, -40.5, 360 - exp)); + } else + { + return (int) Math.floor(solveParabola(4.5, -162.5, 2220 - exp)); + } + } + + public static double solveParabola(double a, double b, double c) + { + return (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java index 194c6fde..f07871bd 100644 --- a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java +++ b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java @@ -1,19 +1,27 @@ package wayoftime.bloodmagic.util.handler.event; +import java.util.Map.Entry; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.Tags; import net.minecraftforge.common.ToolType; import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.entity.player.PlayerXpEvent; import net.minecraftforge.event.world.BlockEvent.BlockToolInteractEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import wayoftime.bloodmagic.BloodMagic; import wayoftime.bloodmagic.api.item.IBindable; import wayoftime.bloodmagic.common.block.BloodMagicBlocks; +import wayoftime.bloodmagic.common.item.ItemExperienceBook; import wayoftime.bloodmagic.core.data.Binding; import wayoftime.bloodmagic.core.data.SoulNetwork; import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; @@ -88,6 +96,48 @@ public class GenericHandler } } + // Experience Tome + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onExperiencePickup(PlayerXpEvent.PickupXp event) + { + PlayerEntity player = event.getPlayer(); + Entry entry = EnchantmentHelper.getRandomItemWithEnchantment(Enchantments.MENDING, player); + + if (entry != null) + { + ItemStack itemStack = entry.getValue(); + if (!itemStack.isEmpty() && itemStack.isDamaged()) + { + int i = Math.min(xpToDurability(event.getOrb().xpValue), itemStack.getDamage()); + event.getOrb().xpValue -= durabilityToXp(i); + itemStack.setDamage(itemStack.getDamage() - i); + } + } + + if (!player.getEntityWorld().isRemote) + { + for (ItemStack stack : player.inventory.mainInventory) + { + if (stack.getItem() instanceof ItemExperienceBook) + { + ItemExperienceBook.addExperience(stack, event.getOrb().xpValue); + event.getOrb().xpValue = 0; + break; + } + } + } + } + + private static int xpToDurability(int xp) + { + return xp * 2; + } + + private static int durabilityToXp(int durability) + { + return durability / 2; + } + public static void sendPlayerDemonWillAura(PlayerEntity player) { if (player instanceof ServerPlayerEntity)