mana is now taken directly from amethyst crystals
83
slushfile.txt
Normal file
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/handheld",
|
||||
"textures": {
|
||||
"layer0": "hex:item/amethyst_dust"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/handheld",
|
||||
"textures": {
|
||||
"layer0": "hex:item/charged_amethyst"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"entries": [
|
||||
"hex:amethyst_cluster"
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Item> 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}"
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
86
src/main/java/at/petrak/hex/common/casting/ManaHelper.kt
Normal file
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ object OpAddMotion : SpellOperator {
|
|||
val motion = args.getChecked<Vec3>(1)
|
||||
return Pair(
|
||||
Spell(target, motion),
|
||||
motion.lengthSqr().toInt() * 100_000
|
||||
(motion.lengthSqr() * 100_000f).toInt()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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<T : ItemPackagedSpell>(val type: Class<T>, val cost: Int) : SpellOperator {
|
||||
override val argc = 1
|
||||
override val argc = 2
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<RenderedSpell, Int> {
|
||||
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<List<SpellDatum<*>>>(0).map { it.tryGet<HexPattern>() }
|
||||
return Pair(Spell(patterns), cost)
|
||||
val entity = args.getChecked<Entity>(0)
|
||||
val patterns = args.getChecked<List<SpellDatum<*>>>(1).map { it.tryGet<HexPattern>() }
|
||||
|
||||
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<HexPattern>) : RenderedSpell {
|
||||
private data class Spell(val itemEntity: ItemEntity, val patterns: List<HexPattern>) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand)
|
||||
if (otherHandItem.item is ItemPackagedSpell) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ItemStack> items) {
|
||||
// Make the wand spawn with some sensible NBT
|
||||
for (Pair<Integer, RegistryObject<Item>> 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<Item> WAND = ITEMS.register(LibItemNames.WAND,
|
||||
() -> new ItemWand(new Item.Properties().stacksTo(1)));
|
||||
() -> new ItemWand(unstackable()));
|
||||
public static final RegistryObject<Item> FOCUS = ITEMS.register(LibItemNames.FOCUS,
|
||||
() -> new ItemFocus(props()));
|
||||
public static final RegistryObject<Item> SPELLBOOK = ITEMS.register(LibItemNames.SPELLBOOK,
|
||||
() -> new ItemSpellbook(unstackable()));
|
||||
public static final RegistryObject<Item> CYPHER = ITEMS.register(LibItemNames.CYPHER,
|
||||
() -> new ItemCypher(new Item.Properties().stacksTo(1)));
|
||||
() -> new ItemCypher(unstackable()));
|
||||
public static final RegistryObject<Item> TRINKET = ITEMS.register(LibItemNames.TRINKET,
|
||||
() -> new ItemTrinket(new Item.Properties().stacksTo(1)));
|
||||
() -> new ItemTrinket(unstackable()));
|
||||
public static final RegistryObject<Item> ARTIFACT = ITEMS.register(LibItemNames.ARTIFACT,
|
||||
() -> new ItemArtifact(new Item.Properties().stacksTo(1)));
|
||||
() -> new ItemArtifact(unstackable()));
|
||||
public static final RegistryObject<Item> AMETHYST_DUST = ITEMS.register(LibItemNames.AMETHYST_DUST,
|
||||
() -> new Item(props()));
|
||||
public static final RegistryObject<Item> CHARGED_AMETHYST = ITEMS.register(LibItemNames.CHARGED_AMETHYST,
|
||||
() -> new Item(props()));
|
||||
|
||||
public static Item.Properties props() {
|
||||
return new Item.Properties().tab(TAB);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<ItemStack> use(Level world, Player player, InteractionHand hand) {
|
||||
if (world.isClientSide()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<ItemStack> 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<HexPattern> getPatterns(CompoundTag tag) {
|
||||
var out = new ArrayList<HexPattern>();
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -18,5 +18,7 @@ public class DataGenerators {
|
|||
if (ev.includeServer()) {
|
||||
// recipes
|
||||
}
|
||||
// On both sides
|
||||
gen.addProvider(new LootModifiers(gen));
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
89
src/main/java/at/petrak/hex/datagen/LootModifiers.java
Normal file
|
@ -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<GlobalLootModifierSerializer<?>> LOOT_MODS = DeferredRegister.create(
|
||||
ForgeRegistries.LOOT_MODIFIER_SERIALIZERS, HexMod.MOD_ID);
|
||||
private static final RegistryObject<AmethystClusterModifier.Serializer> 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<ItemStack> doApply(List<ItemStack> 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<AmethystClusterModifier> {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
BIN
src/main/resources/assets/hex/textures/item/amethyst_dust.png
Normal file
After Width: | Height: | Size: 380 B |
BIN
src/main/resources/assets/hex/textures/item/amethyst_shard.png
Normal file
After Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 611 B After Width: | Height: | Size: 603 B |
BIN
src/main/resources/assets/hex/textures/item/charged_amethyst.png
Normal file
After Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 431 B |
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 272 B |