diff --git a/slushfile.txt b/slushfile.txt new file mode 100644 index 00000000..d0d7badb --- /dev/null +++ b/slushfile.txt @@ -0,0 +1,83 @@ +Mana +- Mana is mental energy/thought +- Mana can be generated by: + = natural growth of amethyst crystals + = lightning? + = XP? + = organics -> corpses, shrubs? (anything edible + anything compostable?) +- Mana generation turns amethyst into perfect crystals, recharges batteries + +Amethyst +- Amethyst stores mana +- Amethyst comes in dust, crystals, perfect crystals +- Each type is worth X mana; must consume an entire item; use up mana producing items least->greatest +- Later-game create rechargeable mana batteries? + +Wandless Spellcasting +- do away with trinkets +- cyphers start with X mana crystals inside and cannot replace them +- artifacts can replace the mana crystals inside as they break +- these are special in that they can partially consume crystals + +Per-world patterns +- all spells are like this? +- only great spells are like this? +- find the patterns on scrolls in chests + +CastException +- Tiers of spell mishaps: + = puff of smoke, drop your wand + = consume a lot of mana, drop all your items + = just kill you, something apt for a great spell +- Mishap based on the type of exception +- item that gives you more detail on the precise manner of the exception + +Great Spells +- require some kind of answer to a question to cast successfully + (see young wizards calculating oxygen amounts to teleport to the moon) +- https://www.dandwiki.com/wiki/SRD:Epic_Spells_and_Powers +- greater teleport: + = total items in inventory? (see chronometer fablehaven not taking your clothes with you) + = some irritating math question about the specific vector involved? + = review eragon's teleportation spell, D&D teleport, oathgates +- flight + = you must be on the ground within X seconds or you take infinite fall damage +- quarry region +- power word kill + +Great Work +- Way to generate infinite mana + = recharge wands/batteries upon touching them? +- borrow from FMA and require the death of 100+ entities at once? (And if not, it gets the caster?) +- nigredo albedo citrinas rubedo? + > Nigredo is the dissolution of the false self; the burning of the old to ashes + > Albedo is the "raising" of the remains to the heavenly sphere in gaseous form; take the ashes and make them reborn + > Citrinas is an optional step but it boils down to some form of "aging" or "wisdom" (which comes with age); + take the newborn (true) self and temper it with time and/or knowledge + > Rubedo is the final distillation; you take the results from albedo/citrinas and you compress them down to a usable + form, the stone + -- alwinfy +- instructions in the form of an emerald-tablet-esque riddle + = include one line on each spell scroll + = assemble the poem, crack the riddle, &c +- possible workflow: + = Cast the first half of the spell, requiring an enumeration of your sins: + + numbers of villagers killed? + + number of passives killed? + + total damage dealt? + You must have no items and no XP (caveat for keepInventory players: under 1 level of XP) + = Timer starts (Witness-esque music track?) + = Nigredo: endure 10 seconds of Wither and 10 seconds of constant fire without picking up any items. + = Albedo: + + teleport 64 blocks in the air and survive the fall? + + gain levitation for X seconds; by the time you hit the floor you must have done Y? + + cure a zombie villager? + = Citrinitas: + + Fight a bunch of mobs? + + Must have 30+ XP levels to cast the second half? + = Cast the second half of the spell, requiring an enumeration of your accomplishments: + + diamonds mined? + + raids won? + + spells cast? + + undead slain? + = Rubedo: Attain the Great Work. \ No newline at end of file diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 69a6867c..766eff6d 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -1,5 +1,7 @@ +72b0863df1de5bd50917aa626e6a27933cc7c485 assets/hex/models/item/amethyst_dust.json a310c1d496f4930955d1484ff271487d811bafd4 assets/hex/models/item/artifact.json 007d82b95d0c976ef5e1f726542ae752111efb8b assets/hex/models/item/artifact_filled.json +c3bfbb78256d5698e5df065e5fcbb1fcddb0505a assets/hex/models/item/charged_amethyst.json fcd283e7b444ffacb8ba71462d2a0aff383fe4a2 assets/hex/models/item/cypher.json 9dcb4967450238440e0db6b25e81a6d9704d4835 assets/hex/models/item/cypher_filled.json 17b322e41c7789c5e6e91b53f7821446d7de6714 assets/hex/models/item/focus.json @@ -21,3 +23,5 @@ a354a2dc83d220c43d4c9f156059cbd8255e9e19 assets/hex/models/item/spellbook.json eaddd1e5ae74293d784748e56e4a238a7607e34c assets/hex/models/item/trinket.json f0cce957861ee854cbd68984015da2c530c9ef6d assets/hex/models/item/trinket_filled.json 837e7ed749afa44bd3be4114c7d81f3b8fe47852 assets/hex/models/item/wand.json +2ac42506f03235f4335dd62f0d6a0c4f23ca61b9 data/forge/loot_modifiers/global_loot_modifiers.json +a46281d65532086be7fbb63beb8c515edf2baaee data/hex/loot_modifiers/amethyst_cluster.json diff --git a/src/generated/resources/assets/hex/models/item/amethyst_dust.json b/src/generated/resources/assets/hex/models/item/amethyst_dust.json new file mode 100644 index 00000000..65c4d543 --- /dev/null +++ b/src/generated/resources/assets/hex/models/item/amethyst_dust.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "hex:item/amethyst_dust" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/hex/models/item/charged_amethyst.json b/src/generated/resources/assets/hex/models/item/charged_amethyst.json new file mode 100644 index 00000000..f9789b9f --- /dev/null +++ b/src/generated/resources/assets/hex/models/item/charged_amethyst.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "hex:item/charged_amethyst" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/forge/loot_modifiers/global_loot_modifiers.json b/src/generated/resources/data/forge/loot_modifiers/global_loot_modifiers.json new file mode 100644 index 00000000..80c79790 --- /dev/null +++ b/src/generated/resources/data/forge/loot_modifiers/global_loot_modifiers.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "entries": [ + "hex:amethyst_cluster" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/hex/loot_modifiers/amethyst_cluster.json b/src/generated/resources/data/hex/loot_modifiers/amethyst_cluster.json new file mode 100644 index 00000000..39e0599c --- /dev/null +++ b/src/generated/resources/data/hex/loot_modifiers/amethyst_cluster.json @@ -0,0 +1,23 @@ +{ + "conditions": [ + { + "condition": "forge:loot_table_id", + "loot_table_id": "minecraft:blocks/amethyst_cluster" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch" + } + ] + } + } + } + ], + "chargedChance": 0.95, + "type": "hex:amethyst_cluster" +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hex/HexConfig.java b/src/main/java/at/petrak/hex/HexConfig.java index ae4df538..509e5331 100644 --- a/src/main/java/at/petrak/hex/HexConfig.java +++ b/src/main/java/at/petrak/hex/HexConfig.java @@ -8,35 +8,27 @@ public class HexConfig { public final ForgeConfigSpec.DoubleValue healthToManaRate; - public final ForgeConfigSpec.IntValue wandMaxMana; - public final ForgeConfigSpec.IntValue wandRechargeRate; - public final ForgeConfigSpec.IntValue cypherMaxMana; - public final ForgeConfigSpec.IntValue trinketMaxMana; - public final ForgeConfigSpec.IntValue artifactMaxMana; - public final ForgeConfigSpec.IntValue artifactRechargeRate; + public final ForgeConfigSpec.IntValue batteryMaxMana; + public final ForgeConfigSpec.IntValue dustManaAmount; + public final ForgeConfigSpec.IntValue shardManaAmount; + public final ForgeConfigSpec.IntValue chargedCrystalManaAmount; public final ForgeConfigSpec.IntValue opBreakHarvestLevel; public final ForgeConfigSpec.IntValue maxRecurseDepth; public HexConfig(ForgeConfigSpec.Builder builder) { - - healthToManaRate = builder.comment("How many points of mana a half-heart is worth when casting from HP") - .defineInRange("healthToManaRate", 1_000_000.0 / 20.0, 0.0, 1_000_000.0); + .defineInRange("healthToManaRate", 1_000_000.0 / 20.0, 0.0, Double.POSITIVE_INFINITY); builder.push("items"); - wandMaxMana = builder.comment("The maximum amount of mana a wand can store.") - .defineInRange("wandMaxMana", 1_000_000, 0, Integer.MAX_VALUE); - wandRechargeRate = builder.comment("How many mana points a wand recharges per tick") - .defineInRange("wandRechargeRate", 2_000, 0, Integer.MAX_VALUE); - cypherMaxMana = builder.comment("The maximum amount of mana a cypher can store.") - .defineInRange("cypherMaxMana", 8_000_000, 0, Integer.MAX_VALUE); - trinketMaxMana = builder.comment("The maximum amount of mana a trinket can store.") - .defineInRange("trinketMaxMana", 4_000_000, 0, Integer.MAX_VALUE); - artifactMaxMana = builder.comment("The maximum amount of mana an artifact can store.") - .defineInRange("artifactMaxMana", 1_000_000, 0, Integer.MAX_VALUE); - artifactRechargeRate = builder.comment("How many mana points an artifact recharges per tick") - .defineInRange("artifactRechargeRate", 1_500, 0, Integer.MAX_VALUE); + batteryMaxMana = builder.comment("The maximum amount of mana a mana battery can store.") + .defineInRange("batteryMaxMana", 1_000_000, 0, Integer.MAX_VALUE); + dustManaAmount = builder.comment("How much mana a single Amethyst Dust item is worth") + .defineInRange("dustManaAmount", 100_000, 0, Integer.MAX_VALUE); + shardManaAmount = builder.comment("How much mana a single Amethyst Shard item is worth") + .defineInRange("shardManaAmount", 500_000, 0, Integer.MAX_VALUE); + chargedCrystalManaAmount = builder.comment("How much mana a single Charged Amethyst Crystal item is worth") + .defineInRange("chargedCrystalManaAmount", 1_000_000, 0, Integer.MAX_VALUE); builder.pop(); builder.push("spells"); diff --git a/src/main/java/at/petrak/hex/HexMod.java b/src/main/java/at/petrak/hex/HexMod.java index fe5aaa28..bae71eb6 100644 --- a/src/main/java/at/petrak/hex/HexMod.java +++ b/src/main/java/at/petrak/hex/HexMod.java @@ -1,8 +1,9 @@ package at.petrak.hex; -import at.petrak.hex.common.casting.RegisterPatterns; import at.petrak.hex.common.items.HexItems; +import at.petrak.hex.common.lib.RegisterPatterns; import at.petrak.hex.common.network.HexMessages; +import at.petrak.hex.datagen.LootModifiers; import at.petrak.hex.server.TickScheduler; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.MinecraftForge; @@ -35,6 +36,7 @@ public class HexMod { HexItems.ITEMS.register(evbus); HexMessages.register(); MinecraftForge.EVENT_BUS.register(TickScheduler.INSTANCE); + LootModifiers.LOOT_MODS.register(evbus); evbus.register(RegisterPatterns.class); } diff --git a/src/main/java/at/petrak/hex/client/RegisterClientStuff.java b/src/main/java/at/petrak/hex/client/RegisterClientStuff.java index 54d114b8..a16a2ee6 100644 --- a/src/main/java/at/petrak/hex/client/RegisterClientStuff.java +++ b/src/main/java/at/petrak/hex/client/RegisterClientStuff.java @@ -4,7 +4,7 @@ import at.petrak.hex.HexMod; import at.petrak.hex.common.casting.SpellDatum; import at.petrak.hex.common.items.HexItems; import at.petrak.hex.common.items.ItemFocus; -import at.petrak.hex.common.items.ItemPackagedSpell; +import at.petrak.hex.common.items.magic.ItemPackagedSpell; import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.world.item.Item; import net.minecraftforge.api.distmarker.Dist; diff --git a/src/main/java/at/petrak/hex/common/casting/CastException.kt b/src/main/java/at/petrak/hex/common/casting/CastException.kt index 3454003f..a449b8d6 100644 --- a/src/main/java/at/petrak/hex/common/casting/CastException.kt +++ b/src/main/java/at/petrak/hex/common/casting/CastException.kt @@ -1,6 +1,7 @@ package at.petrak.hex.common.casting import at.petrak.hex.hexmath.HexPattern +import net.minecraft.core.BlockPos import net.minecraft.world.phys.Vec3 class CastException(val reason: Reason, vararg val data: Any) : Exception() { @@ -64,6 +65,13 @@ class CastException(val reason: Reason, vararg val data: Any) : Exception() { * `Class expected, ItemStack got` */ BAD_OFFHAND_ITEM, + + /** + * Required an inventory at the given position. + * + * `BlockPos pos` + */ + REQUIRES_INVENTORY } override val message: String @@ -76,5 +84,6 @@ class CastException(val reason: Reason, vararg val data: Any) : Exception() { Reason.TOO_FAR -> "tried to interact with something too far away at ${this.data[0] as Vec3}" Reason.TOO_MANY_RECURSIVE_EVALS -> "can only recursively call OpEval ${this.data[0] as Int} times but called it ${this.data[1] as Int} times" Reason.BAD_OFFHAND_ITEM -> "operator expected ${(this.data[0] as Class<*>).typeName} in offhand but got ${this.data[1]}" + Reason.REQUIRES_INVENTORY -> "required an inventory at ${this.data[0] as BlockPos}" } } \ No newline at end of file diff --git a/src/main/java/at/petrak/hex/common/casting/CastingContext.kt b/src/main/java/at/petrak/hex/common/casting/CastingContext.kt index 01c3dfce..1f66d21a 100644 --- a/src/main/java/at/petrak/hex/common/casting/CastingContext.kt +++ b/src/main/java/at/petrak/hex/common/casting/CastingContext.kt @@ -4,8 +4,9 @@ import at.petrak.hex.HexMod import at.petrak.hex.HexUtils import at.petrak.hex.api.Operator import at.petrak.hex.common.items.ItemDataHolder -import at.petrak.hex.common.items.ItemManaHolder import at.petrak.hex.common.items.ItemSpellbook +import at.petrak.hex.common.items.ItemWand +import at.petrak.hex.common.items.magic.ItemPackagedSpell import at.petrak.hex.common.lib.LibDamageSources import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerPlayer @@ -13,6 +14,7 @@ import net.minecraft.world.InteractionHand import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.phys.Vec3 +import java.util.* import java.util.function.Predicate import kotlin.math.min @@ -64,22 +66,40 @@ data class CastingContext( /** * Might cast from hitpoints. - * Returns the mana cost still remaining after we deplete everything. It will be <= 0 if we could pay for it. */ + * Returns the mana cost still remaining after we deplete everything. It will be <= 0 if we could pay for it. + */ fun withdrawMana(manaCost: Int, allowOvercast: Boolean): Int { + if (this.caster.isCreative) return 0 var costLeft = manaCost - val held = caster.getItemInHand(this.castingHand) - val tag = held.orCreateTag - val item = held.item - if (item is ItemManaHolder) { - costLeft = item.withdrawMana(tag, manaCost) + val casterStack = this.caster.getItemInHand(this.castingHand) + val casterItem = casterStack.item + val ipsCanDrawFromInv = if (casterItem is ItemPackagedSpell) { + val tag = casterStack.orCreateTag + val manaAvailable = tag.getInt(ItemPackagedSpell.TAG_MANA) + val manaToTake = min(costLeft, manaAvailable) + tag.putInt(ItemPackagedSpell.TAG_MANA, manaAvailable - manaToTake) + costLeft -= manaToTake + casterItem.canDrawManaFromInventory() + } else { + false } + if (casterItem is ItemWand || ipsCanDrawFromInv) { + val manableItems = this.caster.inventory.items + .filter { !Objects.isNull(ManaHelper.priority(it)) } + .sortedByDescending(ManaHelper::priority) + for (stack in manableItems) { + costLeft -= ManaHelper.extractMana(stack, costLeft)!! + if (costLeft <= 0) + return costLeft + } + } + if (allowOvercast && costLeft > 0) { // Cast from HP! val healthToMana = HexMod.CONFIG.healthToManaRate.get() val healthtoRemove = healthToMana * costLeft.toDouble() - val manaAbleToCastFromHP = - if (caster.isInvulnerable) Double.POSITIVE_INFINITY else caster.health / healthToMana + val manaAbleToCastFromHP = caster.health / healthToMana caster.hurt(LibDamageSources.OVERCAST, healthtoRemove.toFloat()) costLeft = (costLeft.toDouble() - manaAbleToCastFromHP).toInt() } diff --git a/src/main/java/at/petrak/hex/common/casting/ManaHelper.kt b/src/main/java/at/petrak/hex/common/casting/ManaHelper.kt new file mode 100644 index 00000000..75bf3679 --- /dev/null +++ b/src/main/java/at/petrak/hex/common/casting/ManaHelper.kt @@ -0,0 +1,86 @@ +package at.petrak.hex.common.casting + +import at.petrak.hex.HexMod +import at.petrak.hex.common.items.HexItems +import net.minecraft.util.Mth +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import kotlin.math.ceil +import kotlin.math.min +import kotlin.math.roundToInt + +object ManaHelper { + /** + * Try to extract the given amount of mana from this item. + * This may mutate the itemstack. + * + * Return the actual amount of mana extracted, or null if this cannot have mana extracted. + */ + fun extractMana(stack: ItemStack, cost: Int): Int? { + val base = when (stack.item) { + HexItems.AMETHYST_DUST.get() -> HexMod.CONFIG.dustManaAmount.get() + Items.AMETHYST_SHARD -> HexMod.CONFIG.shardManaAmount.get() + HexItems.CHARGED_AMETHYST.get() -> HexMod.CONFIG.chargedCrystalManaAmount.get() + else -> return null + } + val itemsReqd = ceil(cost.toFloat() / base.toFloat()).toInt() + val actualItemsConsumed = min(stack.count, itemsReqd) + stack.shrink(actualItemsConsumed) + return base * actualItemsConsumed + } + + /** + * Extract the entirety of the mana out of this. + * This may mutate the itemstack (and will probably consume it). + * + * Return the amount of mana extracted, or null if this cannot have mana extracted. + */ + fun extractAllMana(stack: ItemStack): Int? { + val base = when (stack.item) { + HexItems.AMETHYST_DUST.get() -> HexMod.CONFIG.dustManaAmount.get() + Items.AMETHYST_SHARD -> HexMod.CONFIG.shardManaAmount.get() + HexItems.CHARGED_AMETHYST.get() -> HexMod.CONFIG.chargedCrystalManaAmount.get() + else -> return null + } + val count = stack.count + stack.shrink(count) + return base * count + } + + /** + * Return the "priority" this should have mana extracted with. + * Higher numbers mean it should be extracted more eagerly. + * Null means it isn't a mana item. + */ + fun priority(stack: ItemStack): Int? { + val base = 100 * when (stack.item) { + HexItems.CHARGED_AMETHYST.get() -> 1 + Items.AMETHYST_SHARD -> 2 + HexItems.AMETHYST_DUST.get() -> 3 + else -> return null + } + return base + stack.count + } + + fun barColor(mana: Int, maxMana: Int): Int { + val amt = if (maxMana == 0) { + 0f + } else { + mana.toFloat() / maxMana.toFloat() + } + + val r = Mth.lerp(amt, 84f, 254f) + val g = Mth.lerp(amt, 57f, 203f) + val b = Mth.lerp(amt, 138f, 230f) + return Mth.color(r / 255f, g / 255f, b / 255f) + } + + fun barWidth(mana: Int, maxMana: Int): Int { + val amt = if (maxMana == 0) { + 0f + } else { + mana.toFloat() / maxMana.toFloat() + } + return (13f * amt).roundToInt() + } +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpAddMotion.kt b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpAddMotion.kt index d7073e0c..ab7d9963 100644 --- a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpAddMotion.kt +++ b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpAddMotion.kt @@ -21,7 +21,7 @@ object OpAddMotion : SpellOperator { val motion = args.getChecked(1) return Pair( Spell(target, motion), - motion.lengthSqr().toInt() * 100_000 + (motion.lengthSqr() * 100_000f).toInt() ) } diff --git a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpBreakBlock.kt b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpBreakBlock.kt index dc153601..3856386e 100644 --- a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpBreakBlock.kt +++ b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpBreakBlock.kt @@ -31,10 +31,11 @@ object OpBreakBlock : SpellOperator { val tier = HexMod.CONFIG.opBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort - if (!blockstate.isAir && (!blockstate.requiresCorrectToolForDrops() || TierSortingRegistry.isCorrectTierForDrops( - tier, - blockstate - )) + if ( + !blockstate.isAir + && blockstate.getDestroySpeed(ctx.world, pos) >= 0f + && (!blockstate.requiresCorrectToolForDrops() + || TierSortingRegistry.isCorrectTierForDrops(tier, blockstate)) ) { ctx.world.destroyBlock(pos, true, ctx.caster) } // TODO: else some kind of failureific particle effect? diff --git a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpMakePackagedSpell.kt b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpMakePackagedSpell.kt index cf37c27f..fa795c7d 100644 --- a/src/main/java/at/petrak/hex/common/casting/operators/spells/OpMakePackagedSpell.kt +++ b/src/main/java/at/petrak/hex/common/casting/operators/spells/OpMakePackagedSpell.kt @@ -2,36 +2,49 @@ package at.petrak.hex.common.casting.operators.spells import at.petrak.hex.api.Operator.Companion.getChecked import at.petrak.hex.api.SpellOperator -import at.petrak.hex.common.casting.CastException -import at.petrak.hex.common.casting.CastingContext -import at.petrak.hex.common.casting.RenderedSpell -import at.petrak.hex.common.casting.SpellDatum -import at.petrak.hex.common.items.ItemPackagedSpell +import at.petrak.hex.common.casting.* +import at.petrak.hex.common.items.magic.ItemPackagedSpell import at.petrak.hex.hexmath.HexPattern import net.minecraft.nbt.ListTag +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.item.ItemEntity class OpMakePackagedSpell(val type: Class, val cost: Int) : SpellOperator { - override val argc = 1 + override val argc = 2 override fun execute(args: List>, ctx: CastingContext): Pair { val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand) if (!type.isAssignableFrom(otherHandItem.item.javaClass)) { throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, type, otherHandItem) } - val patterns = args.getChecked>>(0).map { it.tryGet() } - return Pair(Spell(patterns), cost) + val entity = args.getChecked(0) + val patterns = args.getChecked>>(1).map { it.tryGet() } + + if (entity !is ItemEntity) + throw CastException(CastException.Reason.OP_WRONG_TYPE, ItemEntity::class.java, entity) + + return Pair(Spell(entity, patterns), cost) } - private data class Spell(val patterns: List) : RenderedSpell { + private data class Spell(val itemEntity: ItemEntity, val patterns: List) : RenderedSpell { override fun cast(ctx: CastingContext) { val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand) - if (otherHandItem.item is ItemPackagedSpell) { - val tag = otherHandItem.orCreateTag - val patsTag = ListTag() - for (pat in patterns) { - patsTag.add(pat.serializeToNBT()) + if (otherHandItem.item is ItemPackagedSpell && itemEntity.isAlive) { + val manaAmt = ManaHelper.extractAllMana(itemEntity.item) + if (manaAmt != null) { + val tag = otherHandItem.orCreateTag + tag.putInt(ItemPackagedSpell.TAG_MANA, manaAmt) + tag.putInt(ItemPackagedSpell.TAG_START_MANA, manaAmt) + + val patsTag = ListTag() + for (pat in patterns) { + patsTag.add(pat.serializeToNBT()) + } + tag.put(ItemPackagedSpell.TAG_PATTERNS, patsTag) + + if (itemEntity.item.isEmpty) + itemEntity.kill() } - tag.put(ItemPackagedSpell.TAG_PATTERNS, patsTag) } } } diff --git a/src/main/java/at/petrak/hex/common/items/HexItems.java b/src/main/java/at/petrak/hex/common/items/HexItems.java index 87104cb8..3626ee6f 100644 --- a/src/main/java/at/petrak/hex/common/items/HexItems.java +++ b/src/main/java/at/petrak/hex/common/items/HexItems.java @@ -1,10 +1,11 @@ package at.petrak.hex.common.items; import at.petrak.hex.HexMod; +import at.petrak.hex.common.items.magic.ItemArtifact; +import at.petrak.hex.common.items.magic.ItemCypher; +import at.petrak.hex.common.items.magic.ItemTrinket; import at.petrak.hex.common.lib.LibItemNames; -import com.mojang.datafixers.util.Pair; import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -22,39 +23,26 @@ public class HexItems { @Override public void fillItemList(NonNullList items) { - // Make the wand spawn with some sensible NBT - for (Pair> p : new Pair[]{ - new Pair<>(HexMod.CONFIG.wandMaxMana.get(), WAND), - new Pair<>(HexMod.CONFIG.cypherMaxMana.get(), CYPHER), - new Pair<>(HexMod.CONFIG.trinketMaxMana.get(), TRINKET), - new Pair<>(HexMod.CONFIG.artifactMaxMana.get(), ARTIFACT), - }) { - var mana = p.getFirst(); - var stack = new ItemStack(p.getSecond()::get); - - var tag = new CompoundTag(); - tag.putInt(ItemManaHolder.TAG_MANA, mana); - tag.putInt(ItemWand.TAG_MAX_MANA, mana); - stack.setTag(tag); - items.add(stack); - } - super.fillItemList(items); } }; public static final RegistryObject WAND = ITEMS.register(LibItemNames.WAND, - () -> new ItemWand(new Item.Properties().stacksTo(1))); + () -> new ItemWand(unstackable())); public static final RegistryObject FOCUS = ITEMS.register(LibItemNames.FOCUS, () -> new ItemFocus(props())); public static final RegistryObject SPELLBOOK = ITEMS.register(LibItemNames.SPELLBOOK, () -> new ItemSpellbook(unstackable())); public static final RegistryObject CYPHER = ITEMS.register(LibItemNames.CYPHER, - () -> new ItemCypher(new Item.Properties().stacksTo(1))); + () -> new ItemCypher(unstackable())); public static final RegistryObject TRINKET = ITEMS.register(LibItemNames.TRINKET, - () -> new ItemTrinket(new Item.Properties().stacksTo(1))); + () -> new ItemTrinket(unstackable())); public static final RegistryObject ARTIFACT = ITEMS.register(LibItemNames.ARTIFACT, - () -> new ItemArtifact(new Item.Properties().stacksTo(1))); + () -> new ItemArtifact(unstackable())); + public static final RegistryObject AMETHYST_DUST = ITEMS.register(LibItemNames.AMETHYST_DUST, + () -> new Item(props())); + public static final RegistryObject CHARGED_AMETHYST = ITEMS.register(LibItemNames.CHARGED_AMETHYST, + () -> new Item(props())); public static Item.Properties props() { return new Item.Properties().tab(TAB); diff --git a/src/main/java/at/petrak/hex/common/items/ItemArtifact.java b/src/main/java/at/petrak/hex/common/items/ItemArtifact.java deleted file mode 100644 index bd348ec2..00000000 --- a/src/main/java/at/petrak/hex/common/items/ItemArtifact.java +++ /dev/null @@ -1,28 +0,0 @@ -package at.petrak.hex.common.items; - -import at.petrak.hex.HexMod; -import net.minecraft.nbt.CompoundTag; - -/** - * Multi-use recharging magic item. - */ -public class ItemArtifact extends ItemPackagedSpell { - public ItemArtifact(Properties pProperties) { - super(pProperties); - } - - @Override - boolean singleUse() { - return false; - } - - @Override - int getMaxMana(CompoundTag tag) { - return HexMod.CONFIG.artifactMaxMana.get(); - } - - @Override - int getManaRechargeRate(CompoundTag tag) { - return HexMod.CONFIG.artifactRechargeRate.get(); - } -} diff --git a/src/main/java/at/petrak/hex/common/items/ItemCypher.java b/src/main/java/at/petrak/hex/common/items/ItemCypher.java deleted file mode 100644 index 1d4cfb82..00000000 --- a/src/main/java/at/petrak/hex/common/items/ItemCypher.java +++ /dev/null @@ -1,28 +0,0 @@ -package at.petrak.hex.common.items; - -import at.petrak.hex.HexMod; -import net.minecraft.nbt.CompoundTag; - -/** - * Single-use magic item. - */ -public class ItemCypher extends ItemPackagedSpell { - public ItemCypher(Properties pProperties) { - super(pProperties); - } - - @Override - boolean singleUse() { - return true; - } - - @Override - int getMaxMana(CompoundTag tag) { - return HexMod.CONFIG.cypherMaxMana.get(); - } - - @Override - int getManaRechargeRate(CompoundTag tag) { - return 0; - } -} diff --git a/src/main/java/at/petrak/hex/common/items/ItemManaBattery.java b/src/main/java/at/petrak/hex/common/items/ItemManaBattery.java new file mode 100644 index 00000000..97dfbb62 --- /dev/null +++ b/src/main/java/at/petrak/hex/common/items/ItemManaBattery.java @@ -0,0 +1,62 @@ +package at.petrak.hex.common.items; + +import at.petrak.hex.HexMod; +import at.petrak.hex.common.casting.ManaHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +public class ItemManaBattery extends Item { + public static final String TAG_MANA = "hex.mana"; + + public ItemManaBattery(Properties pProperties) { + super(pProperties); + } + + + public int getMana(CompoundTag tag) { + return tag.getInt(TAG_MANA); + } + + /** + * Return how much mana we lack + */ + public int withdrawMana(CompoundTag tag, int cost) { + var manaHere = getMana(tag); + var manaLeft = manaHere - cost; + tag.putInt(TAG_MANA, Math.max(0, manaLeft)); + return Math.max(0, cost - manaHere); + } + + @Override + public boolean isDamageable(ItemStack stack) { + return false; + } + + @Override + public boolean canBeDepleted() { + return false; + } + + @Override + public boolean isBarVisible(ItemStack pStack) { + return true; + } + + @Override + public int getBarColor(ItemStack pStack) { + var tag = pStack.getOrCreateTag(); + var mana = getMana(tag); + var maxMana = HexMod.CONFIG.batteryMaxMana.get(); + return ManaHelper.INSTANCE.barColor(mana, maxMana); + } + + @Override + public int getBarWidth(ItemStack pStack) { + var tag = pStack.getOrCreateTag(); + var mana = getMana(tag); + var maxMana = HexMod.CONFIG.batteryMaxMana.get(); + return ManaHelper.INSTANCE.barWidth(mana, maxMana); + } + +} diff --git a/src/main/java/at/petrak/hex/common/items/ItemManaHolder.java b/src/main/java/at/petrak/hex/common/items/ItemManaHolder.java deleted file mode 100644 index dc7d394a..00000000 --- a/src/main/java/at/petrak/hex/common/items/ItemManaHolder.java +++ /dev/null @@ -1,88 +0,0 @@ -package at.petrak.hex.common.items; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -public abstract class ItemManaHolder extends Item { - public static final String TAG_MANA = "hex.mana"; - - public ItemManaHolder(Properties pProperties) { - super(pProperties); - } - - abstract int getMaxMana(CompoundTag tag); - - abstract int getManaRechargeRate(CompoundTag tag); - - public int getMana(CompoundTag tag) { - return tag.getInt(TAG_MANA); - } - - /** - * Return how much mana we lack - */ - public int withdrawMana(CompoundTag tag, int cost) { - var manaHere = getMana(tag); - var manaLeft = manaHere - cost; - tag.putInt(TAG_MANA, Math.max(0, manaLeft)); - return Math.max(0, cost - manaHere); - } - - @Override - public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pSlotId, boolean pIsSelected) { - var tag = pStack.getOrCreateTag(); - tag.putInt(TAG_MANA, Math.min(getMana(tag) + getManaRechargeRate(tag), getMaxMana(tag))); - } - - @Override - public boolean isDamageable(ItemStack stack) { - return false; - } - - @Override - public boolean canBeDepleted() { - return false; - } - - @Override - public boolean isBarVisible(ItemStack pStack) { - return true; - } - - @Override - public int getBarColor(ItemStack pStack) { - var tag = pStack.getOrCreateTag(); - var mana = getMana(tag); - var maxMana = getMaxMana(tag); - float amt; - if (maxMana == 0) { - amt = 0f; - } else { - amt = ((float) mana) / ((float) maxMana); - } - - var r = Mth.lerp(amt, 149f, 112f); - var g = Mth.lerp(amt, 196f, 219f); - var b = Mth.lerp(amt, 174f, 212f); - return Mth.color(r / 255f, g / 255f, b / 255f); - } - - @Override - public int getBarWidth(ItemStack pStack) { - var tag = pStack.getOrCreateTag(); - var mana = getMana(tag); - var maxMana = getMaxMana(tag); - float amt; - if (maxMana == 0) { - amt = 0f; - } else { - amt = ((float) mana) / ((float) maxMana); - } - return Math.round(13f * amt); - } - -} diff --git a/src/main/java/at/petrak/hex/common/items/ItemTrinket.java b/src/main/java/at/petrak/hex/common/items/ItemTrinket.java deleted file mode 100644 index 9fd27133..00000000 --- a/src/main/java/at/petrak/hex/common/items/ItemTrinket.java +++ /dev/null @@ -1,28 +0,0 @@ -package at.petrak.hex.common.items; - -import at.petrak.hex.HexMod; -import net.minecraft.nbt.CompoundTag; - -/** - * Multi-use but non-recharging magic item. - */ -public class ItemTrinket extends ItemPackagedSpell { - public ItemTrinket(Properties pProperties) { - super(pProperties); - } - - @Override - boolean singleUse() { - return false; - } - - @Override - int getMaxMana(CompoundTag tag) { - return HexMod.CONFIG.trinketMaxMana.get(); - } - - @Override - int getManaRechargeRate(CompoundTag tag) { - return 0; - } -} diff --git a/src/main/java/at/petrak/hex/common/items/ItemWand.java b/src/main/java/at/petrak/hex/common/items/ItemWand.java index f64b9211..923816f2 100644 --- a/src/main/java/at/petrak/hex/common/items/ItemWand.java +++ b/src/main/java/at/petrak/hex/common/items/ItemWand.java @@ -1,35 +1,22 @@ package at.petrak.hex.common.items; -import at.petrak.hex.HexMod; import at.petrak.hex.client.gui.GuiSpellcasting; import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -public class ItemWand extends ItemManaHolder { - public static final String TAG_MAX_MANA = "maxMana"; +public class ItemWand extends Item { public static final String TAG_HARNESS = "harness"; public ItemWand(Properties pProperties) { super(pProperties); } - @Override - int getMaxMana(CompoundTag tag) { - return tag.getInt(TAG_MAX_MANA); - } - - @Override - int getManaRechargeRate(CompoundTag tag) { - return HexMod.CONFIG.wandRechargeRate.get(); - } - - @Override public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { if (world.isClientSide()) { diff --git a/src/main/java/at/petrak/hex/common/items/magic/ItemArtifact.java b/src/main/java/at/petrak/hex/common/items/magic/ItemArtifact.java new file mode 100644 index 00000000..e82a81d1 --- /dev/null +++ b/src/main/java/at/petrak/hex/common/items/magic/ItemArtifact.java @@ -0,0 +1,17 @@ +package at.petrak.hex.common.items.magic; + +public class ItemArtifact extends ItemPackagedSpell { + public ItemArtifact(Properties pProperties) { + super(pProperties); + } + + @Override + public boolean canDrawManaFromInventory() { + return true; + } + + @Override + public boolean singleUse() { + return false; + } +} diff --git a/src/main/java/at/petrak/hex/common/items/magic/ItemCypher.java b/src/main/java/at/petrak/hex/common/items/magic/ItemCypher.java new file mode 100644 index 00000000..9032e6dc --- /dev/null +++ b/src/main/java/at/petrak/hex/common/items/magic/ItemCypher.java @@ -0,0 +1,17 @@ +package at.petrak.hex.common.items.magic; + +public class ItemCypher extends ItemPackagedSpell { + public ItemCypher(Properties pProperties) { + super(pProperties); + } + + @Override + public boolean canDrawManaFromInventory() { + return false; + } + + @Override + public boolean singleUse() { + return true; + } +} diff --git a/src/main/java/at/petrak/hex/common/items/ItemPackagedSpell.java b/src/main/java/at/petrak/hex/common/items/magic/ItemPackagedSpell.java similarity index 78% rename from src/main/java/at/petrak/hex/common/items/ItemPackagedSpell.java rename to src/main/java/at/petrak/hex/common/items/magic/ItemPackagedSpell.java index 52e8f197..e18f163f 100644 --- a/src/main/java/at/petrak/hex/common/items/ItemPackagedSpell.java +++ b/src/main/java/at/petrak/hex/common/items/magic/ItemPackagedSpell.java @@ -1,8 +1,9 @@ -package at.petrak.hex.common.items; +package at.petrak.hex.common.items.magic; import at.petrak.hex.HexMod; import at.petrak.hex.common.casting.CastingContext; import at.petrak.hex.common.casting.CastingHarness; +import at.petrak.hex.common.casting.ManaHelper; import at.petrak.hex.hexmath.HexPattern; import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; @@ -15,6 +16,7 @@ import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.UseAnim; import net.minecraft.world.level.Level; @@ -25,7 +27,9 @@ import java.util.List; /** * Item that holds a list of patterns in it ready to be cast */ -public abstract class ItemPackagedSpell extends ItemManaHolder { +public abstract class ItemPackagedSpell extends Item { + public static final String TAG_MANA = "hex:mana"; + public static final String TAG_START_MANA = "hex:start_mana"; public static final String TAG_PATTERNS = "patterns"; public static final ResourceLocation HAS_PATTERNS_PRED = new ResourceLocation(HexMod.MOD_ID, "has_patterns"); @@ -33,7 +37,9 @@ public abstract class ItemPackagedSpell extends ItemManaHolder { super(pProperties); } - abstract boolean singleUse(); + public abstract boolean singleUse(); + + public abstract boolean canDrawManaFromInventory(); @Override public InteractionResultHolder use(Level world, Player player, InteractionHand usedHand) { @@ -77,6 +83,7 @@ public abstract class ItemPackagedSpell extends ItemManaHolder { player.getCooldowns().addCooldown(this, 20); if (singleUse()) { + stack.shrink(1); return InteractionResultHolder.consume(stack); } else { return InteractionResultHolder.success(stack); @@ -96,9 +103,24 @@ public abstract class ItemPackagedSpell extends ItemManaHolder { @Override public boolean isBarVisible(ItemStack pStack) { var tag = pStack.getOrCreateTag(); - return !singleUse() && tag.contains(TAG_PATTERNS); + return tag.contains(TAG_PATTERNS); } + @Override + public int getBarColor(ItemStack pStack) { + var tag = pStack.getOrCreateTag(); + var mana = tag.getInt(TAG_MANA); + var maxMana = tag.getInt(TAG_START_MANA); + return ManaHelper.INSTANCE.barColor(mana, maxMana); + } + + @Override + public int getBarWidth(ItemStack pStack) { + var tag = pStack.getOrCreateTag(); + var mana = tag.getInt(TAG_MANA); + var maxMana = tag.getInt(TAG_START_MANA); + return ManaHelper.INSTANCE.barWidth(mana, maxMana); + } private static List getPatterns(CompoundTag tag) { var out = new ArrayList(); diff --git a/src/main/java/at/petrak/hex/common/items/magic/ItemTrinket.java b/src/main/java/at/petrak/hex/common/items/magic/ItemTrinket.java new file mode 100644 index 00000000..b1c8a869 --- /dev/null +++ b/src/main/java/at/petrak/hex/common/items/magic/ItemTrinket.java @@ -0,0 +1,17 @@ +package at.petrak.hex.common.items.magic; + +public class ItemTrinket extends ItemPackagedSpell { + public ItemTrinket(Properties pProperties) { + super(pProperties); + } + + @Override + public boolean canDrawManaFromInventory() { + return false; + } + + @Override + public boolean singleUse() { + return false; + } +} diff --git a/src/main/java/at/petrak/hex/common/lib/LibItemNames.java b/src/main/java/at/petrak/hex/common/lib/LibItemNames.java index c0f179d8..ee1d575c 100644 --- a/src/main/java/at/petrak/hex/common/lib/LibItemNames.java +++ b/src/main/java/at/petrak/hex/common/lib/LibItemNames.java @@ -7,4 +7,6 @@ public class LibItemNames { public static final String CYPHER = "cypher"; public static final String TRINKET = "trinket"; public static final String ARTIFACT = "artifact"; + public static final String AMETHYST_DUST = "amethyst_dust"; + public static final String CHARGED_AMETHYST = "charged_amethyst"; } diff --git a/src/main/java/at/petrak/hex/common/casting/RegisterPatterns.java b/src/main/java/at/petrak/hex/common/lib/RegisterPatterns.java similarity index 95% rename from src/main/java/at/petrak/hex/common/casting/RegisterPatterns.java rename to src/main/java/at/petrak/hex/common/lib/RegisterPatterns.java index 578e4550..4180fbae 100644 --- a/src/main/java/at/petrak/hex/common/casting/RegisterPatterns.java +++ b/src/main/java/at/petrak/hex/common/lib/RegisterPatterns.java @@ -1,14 +1,16 @@ -package at.petrak.hex.common.casting; +package at.petrak.hex.common.lib; import at.petrak.hex.HexMod; import at.petrak.hex.api.Operator; import at.petrak.hex.api.PatternRegistry; +import at.petrak.hex.common.casting.SpellDatum; +import at.petrak.hex.common.casting.Widget; import at.petrak.hex.common.casting.operators.*; import at.petrak.hex.common.casting.operators.math.*; import at.petrak.hex.common.casting.operators.spells.*; -import at.petrak.hex.common.items.ItemArtifact; -import at.petrak.hex.common.items.ItemCypher; -import at.petrak.hex.common.items.ItemTrinket; +import at.petrak.hex.common.items.magic.ItemArtifact; +import at.petrak.hex.common.items.magic.ItemCypher; +import at.petrak.hex.common.items.magic.ItemTrinket; import com.mojang.datafixers.util.Pair; import net.minecraft.world.phys.Vec3; import net.minecraftforge.eventbus.api.SubscribeEvent; diff --git a/src/main/java/at/petrak/hex/datagen/DataGenerators.java b/src/main/java/at/petrak/hex/datagen/DataGenerators.java index fbe432ba..cec3b689 100644 --- a/src/main/java/at/petrak/hex/datagen/DataGenerators.java +++ b/src/main/java/at/petrak/hex/datagen/DataGenerators.java @@ -18,5 +18,7 @@ public class DataGenerators { if (ev.includeServer()) { // recipes } + // On both sides + gen.addProvider(new LootModifiers(gen)); } } \ No newline at end of file diff --git a/src/main/java/at/petrak/hex/datagen/ItemModels.java b/src/main/java/at/petrak/hex/datagen/ItemModels.java index 0d50f487..e7a415c2 100644 --- a/src/main/java/at/petrak/hex/datagen/ItemModels.java +++ b/src/main/java/at/petrak/hex/datagen/ItemModels.java @@ -3,7 +3,7 @@ package at.petrak.hex.datagen; import at.petrak.hex.HexMod; import at.petrak.hex.common.items.HexItems; import at.petrak.hex.common.items.ItemFocus; -import at.petrak.hex.common.items.ItemPackagedSpell; +import at.petrak.hex.common.items.magic.ItemPackagedSpell; import com.mojang.datafixers.util.Pair; import net.minecraft.data.DataGenerator; import net.minecraft.resources.ResourceLocation; @@ -22,6 +22,8 @@ public class ItemModels extends ItemModelProvider { protected void registerModels() { simpleItem(HexItems.WAND.get()); simpleItem(HexItems.SPELLBOOK.get()); + simpleItem(HexItems.AMETHYST_DUST.get()); + simpleItem(HexItems.CHARGED_AMETHYST.get()); String[] focusTypes = new String[]{ "empty", "entity", "double", "vec3", "widget", "list", "pattern" diff --git a/src/main/java/at/petrak/hex/datagen/LootModifiers.java b/src/main/java/at/petrak/hex/datagen/LootModifiers.java new file mode 100644 index 00000000..59d4949f --- /dev/null +++ b/src/main/java/at/petrak/hex/datagen/LootModifiers.java @@ -0,0 +1,89 @@ +package at.petrak.hex.datagen; + +import at.petrak.hex.HexMod; +import at.petrak.hex.common.items.HexItems; +import com.google.gson.JsonObject; +import net.minecraft.advancements.critereon.EnchantmentPredicate; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.advancements.critereon.MinMaxBounds; +import net.minecraft.data.DataGenerator; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.MatchTool; +import net.minecraftforge.common.data.GlobalLootModifierProvider; +import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.loot.LootModifier; +import net.minecraftforge.common.loot.LootTableIdCondition; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class LootModifiers extends GlobalLootModifierProvider { + public static final DeferredRegister> LOOT_MODS = DeferredRegister.create( + ForgeRegistries.LOOT_MODIFIER_SERIALIZERS, HexMod.MOD_ID); + private static final RegistryObject AMETHYST_CLUSTER = LOOT_MODS.register( + "amethyst_cluster", AmethystClusterModifier.Serializer::new); + + public LootModifiers(DataGenerator gen) { + super(gen, HexMod.MOD_ID); + } + + @Override + protected void start() { + add("amethyst_cluster", AMETHYST_CLUSTER.get(), new AmethystClusterModifier(new LootItemCondition[]{ + LootTableIdCondition.builder(new ResourceLocation("minecraft:blocks/amethyst_cluster")).build(), + MatchTool.toolMatches( + ItemPredicate.Builder.item().hasEnchantment( + new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY))) + .invert().build(), + }, 0.95f)); + } + + public static final class AmethystClusterModifier extends LootModifier { + private final float chargedChance; + + public AmethystClusterModifier(LootItemCondition[] conditions, float chargedChance) { + super(conditions); + this.chargedChance = chargedChance; + } + + @NotNull + @Override + protected List doApply(List generatedLoot, LootContext context) { + var rand = context.getRandom(); + var tool = context.getParamOrNull(LootContextParams.TOOL); + var fortuneLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool); + var dustCount = 1 + Math.round(rand.nextFloat() * fortuneLevel); + var hasCharged = (rand.nextFloat() * (fortuneLevel / 2f + 1)) > this.chargedChance; + + generatedLoot.add(new ItemStack(HexItems.AMETHYST_DUST.get(), dustCount)); + generatedLoot.add(new ItemStack(HexItems.CHARGED_AMETHYST.get(), hasCharged ? 1 : 0)); + return generatedLoot; + } + + private static class Serializer extends GlobalLootModifierSerializer { + @Override + public AmethystClusterModifier read(ResourceLocation location, JsonObject object, + LootItemCondition[] conditions) { + var chargedChance = GsonHelper.getAsFloat(object, "chargedChance"); + return new AmethystClusterModifier(conditions, chargedChance); + } + + @Override + public JsonObject write(AmethystClusterModifier instance) { + var obj = makeConditions(instance.conditions); + obj.addProperty("chargedChance", instance.chargedChance); + return obj; + } + } + } +} diff --git a/src/main/resources/assets/hex/lang/en_US.json b/src/main/resources/assets/hex/lang/en_US.json index 29cacd64..d50c86d4 100644 --- a/src/main/resources/assets/hex/lang/en_US.json +++ b/src/main/resources/assets/hex/lang/en_US.json @@ -5,6 +5,8 @@ "item.hex.cypher": "Cypher", "item.hex.trinket": "Trinket", "item.hex.artifact": "Artifact", + "item.hex.amethyst_dust": "Amethyst Dust", + "item.hex.charged_amethyst": "Charged Amethyst Crystal", "death.attack.hex.overcast": "%s's mind was consumed into energy", "hex.spellbook.tooltip.page": "Selected Page %d/%d", diff --git a/src/main/resources/assets/hex/textures/item/amethyst_dust.png b/src/main/resources/assets/hex/textures/item/amethyst_dust.png new file mode 100644 index 00000000..f1ea44d6 Binary files /dev/null and b/src/main/resources/assets/hex/textures/item/amethyst_dust.png differ diff --git a/src/main/resources/assets/hex/textures/item/amethyst_shard.png b/src/main/resources/assets/hex/textures/item/amethyst_shard.png new file mode 100644 index 00000000..9c842989 Binary files /dev/null and b/src/main/resources/assets/hex/textures/item/amethyst_shard.png differ diff --git a/src/main/resources/assets/hex/textures/item/artifact.png b/src/main/resources/assets/hex/textures/item/artifact.png index 92fecf55..7bf3d9ee 100644 Binary files a/src/main/resources/assets/hex/textures/item/artifact.png and b/src/main/resources/assets/hex/textures/item/artifact.png differ diff --git a/src/main/resources/assets/hex/textures/item/artifact_filled.png b/src/main/resources/assets/hex/textures/item/artifact_filled.png index ae9740af..3d5b112a 100644 Binary files a/src/main/resources/assets/hex/textures/item/artifact_filled.png and b/src/main/resources/assets/hex/textures/item/artifact_filled.png differ diff --git a/src/main/resources/assets/hex/textures/item/charged_amethyst.png b/src/main/resources/assets/hex/textures/item/charged_amethyst.png new file mode 100644 index 00000000..ba8cf4e9 Binary files /dev/null and b/src/main/resources/assets/hex/textures/item/charged_amethyst.png differ diff --git a/src/main/resources/assets/hex/textures/item/spellbook.png b/src/main/resources/assets/hex/textures/item/spellbook.png index f14d6acd..37b3cbd6 100644 Binary files a/src/main/resources/assets/hex/textures/item/spellbook.png and b/src/main/resources/assets/hex/textures/item/spellbook.png differ diff --git a/src/main/resources/assets/hex/textures/item/trinket.png b/src/main/resources/assets/hex/textures/item/trinket.png index f725db24..8cb2b9a6 100644 Binary files a/src/main/resources/assets/hex/textures/item/trinket.png and b/src/main/resources/assets/hex/textures/item/trinket.png differ diff --git a/src/main/resources/assets/hex/textures/item/trinket_filled.png b/src/main/resources/assets/hex/textures/item/trinket_filled.png index 418fc3db..d088599c 100644 Binary files a/src/main/resources/assets/hex/textures/item/trinket_filled.png and b/src/main/resources/assets/hex/textures/item/trinket_filled.png differ diff --git a/src/main/resources/assets/hex/textures/item/wand.png b/src/main/resources/assets/hex/textures/item/wand.png index 1c2d3dcc..eea96e6f 100644 Binary files a/src/main/resources/assets/hex/textures/item/wand.png and b/src/main/resources/assets/hex/textures/item/wand.png differ