1
0
mirror of https://github.com/chylex/Hardcore-Ender-Expansion-2.git synced 2025-04-11 03:15:44 +02:00

Fix several issues with Potions (typos in recipes, compatibility with old worlds)

This commit is contained in:
chylex 2019-08-07 15:53:25 +02:00
parent 005e467373
commit bab34fd36f
5 changed files with 141 additions and 66 deletions
src/main/java/chylex/hee

View File

@ -2,6 +2,7 @@ package chylex.hee.game.mechanics.potion.brewing
import chylex.hee.game.mechanics.potion.PotionPurity.PURITY
import chylex.hee.game.mechanics.potion.brewing.PotionTypeInfo.Duration
import chylex.hee.init.ModItems.DRAGON_SCALE
import chylex.hee.system.util.floorToInt
import net.minecraft.init.Items.BLAZE_POWDER
import net.minecraft.init.Items.FERMENTED_SPIDER_EYE
import net.minecraft.init.Items.FISH
@ -35,27 +36,27 @@ import net.minecraft.potion.PotionUtils
object PotionBrewing{
val INFO = arrayOf(
PotionTypeInfo(INSTANT_HEALTH, maxLevel = 2),
PotionTypeInfo(FIRE_RESISTANCE, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(REGENERATION, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 3),
PotionTypeInfo(STRENGTH, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(SPEED, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(NIGHT_VISION, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(WATER_BREATHING, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(JUMP_BOOST, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(POISON, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 2),
// UPDATE PotionTypeInfo(TURTLE_MASTER, Duration(baseTicks = 0 min 20, stepTicks = 13 s 7, maxSteps = 3), maxLevel = 2),
// UPDATE PotionTypeInfo(SLOW_FALLING, Duration(baseTicks = 1 min 15, stepTicks = 1 min 15, maxSteps = 3), maxLevel = 1),
PotionTypeInfo(LEVITATION, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 2),
PotionTypeInfo(PURITY, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
// TODO PotionTypeInfo(CORRUPTION, Duration(baseTicks = 0 min 20, stepTicks = 13 s 7, maxSteps = 3), maxLevel = 1),
PotionTypeInfo(BLINDNESS, Duration(baseTicks = 0 min 20, stepTicks = 13 s 7, maxSteps = 3), maxLevel = 1),
PotionTypeInfo(WEAKNESS, Duration(baseTicks = 1 min 15, stepTicks = 1 min 15, maxSteps = 3), maxLevel = 3),
PotionTypeInfo(FIRE_RESISTANCE, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(REGENERATION, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 3),
PotionTypeInfo(STRENGTH, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(SPEED, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(NIGHT_VISION, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(WATER_BREATHING, Duration(baseTicks = 3 min 20, stepTicks = 3 min 10, maxSteps = 4), maxLevel = 1),
PotionTypeInfo(JUMP_BOOST, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(POISON, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 2),
// PotionTypeInfo(TURTLE_MASTER, Duration(baseTicks = 0 min 20, stepTicks = 0 min 13.34, maxSteps = 3), maxLevel = 2), // UPDATE
// PotionTypeInfo(SLOW_FALLING, Duration(baseTicks = 1 min 15, stepTicks = 1 min 15, maxSteps = 3), maxLevel = 1), // UPDATE
PotionTypeInfo(LEVITATION, Duration(baseTicks = 0 min 30, stepTicks = 0 min 30, maxSteps = 3), maxLevel = 2),
PotionTypeInfo(PURITY, Duration(baseTicks = 2 min 30, stepTicks = 2 min 15, maxSteps = 4), maxLevel = 3),
// PotionTypeInfo(CORRUPTION, Duration(baseTicks = 0 min 20, stepTicks = 0 min 13.34, maxSteps = 3), maxLevel = 1), // TODO
PotionTypeInfo(BLINDNESS, Duration(baseTicks = 0 min 20, stepTicks = 0 min 13.34, maxSteps = 3), maxLevel = 1),
PotionTypeInfo(WEAKNESS, Duration(baseTicks = 1 min 15, stepTicks = 1 min 15, maxSteps = 3), maxLevel = 3),
PotionTypeInfo(INSTANT_DAMAGE, maxLevel = 2),
PotionTypeInfo(SPEED, Duration(baseTicks = 1 min 15, stepTicks = 1 min 7 s 10, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(INVISIBILITY, Duration(baseTicks = 1 min 20, stepTicks = 1 min 16, maxSteps = 4), maxLevel = 1),
// TODO PotionTypeInfo(BANISHMENT, Duration(baseTicks = 0 min 15, stepTicks = 10 s 0, maxSteps = 3), maxLevel = 1),
PotionTypeInfo(GLOWING, Duration(baseTicks = 0 min 12, stepTicks = 8 s 0, maxSteps = 3), maxLevel = 1)
PotionTypeInfo(SLOWNESS, Duration(baseTicks = 1 min 15, stepTicks = 1 min 7.5, maxSteps = 4), maxLevel = 3),
PotionTypeInfo(INVISIBILITY, Duration(baseTicks = 1 min 20, stepTicks = 1 min 16, maxSteps = 4), maxLevel = 1),
// PotionTypeInfo(BANISHMENT, Duration(baseTicks = 0 min 15, stepTicks = 0 min 10, maxSteps = 3), maxLevel = 1), // TODO
PotionTypeInfo(GLOWING, Duration(baseTicks = 0 min 12, stepTicks = 0 min 8, maxSteps = 3), maxLevel = 1)
).associateBy { it.potion }
// TODO register levitation type and other custom potions
@ -115,7 +116,7 @@ object PotionBrewing{
return ((this * 60) + seconds) * 20
}
private infix fun Int.s(ticks: Int): Int{
return (this * 20) + ticks
private infix fun Int.min(seconds: Double): Int{
return (((this * 60) + seconds) * 20).floorToInt()
}
}

View File

@ -42,15 +42,30 @@ object PotionItems{
MobEffects.WEAKNESS to PotionTypes.WEAKNESS
)
val VANILLA_TYPES
private val TYPE_NO_EFFECT_OVERRIDES = mutableMapOf<PotionType, PotionType>()
val ALTERED_TYPES
get() = TYPE_MAPPING.values
fun registerNoEffectOverride(original: PotionType, override: PotionType){
TYPE_NO_EFFECT_OVERRIDES[original] = override
}
fun findNoEffectOverride(type: PotionType): PotionType{
return TYPE_NO_EFFECT_OVERRIDES[type] ?: type
}
fun getBottle(item: Item, type: PotionType): ItemStack{
return PotionUtils.addPotionToItemStack(ItemStack(item), type)
}
fun getBottle(item: Item, potion: Potion): ItemStack{
return getBottle(item, TYPE_MAPPING.getOrDefault(potion, PotionTypes.WATER))
fun getBottle(item: Item, potion: Potion, withBaseEffect: Boolean): ItemStack{
val type = TYPE_MAPPING.getOrDefault(potion, PotionTypes.WATER)
return if (withBaseEffect)
getBottle(item, type)
else
getBottle(item, findNoEffectOverride(type))
}
fun checkBottle(stack: ItemStack, type: PotionType): Boolean{

View File

@ -1,44 +1,61 @@
package chylex.hee.game.mechanics.potion.brewing
import chylex.hee.system.util.floorToInt
import chylex.hee.system.util.getIntegerOrNull
import chylex.hee.system.util.heeTag
import chylex.hee.system.util.heeTagOrNull
import chylex.hee.system.util.nbt
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.potion.Potion
import net.minecraft.potion.PotionEffect
import net.minecraft.potion.PotionUtils
import kotlin.math.abs
class PotionTypeInfo(
val potion: Potion,
private val duration: Duration? = null,
private val maxLevel: Int
){
fun getBasePotion(item: Item): ItemStack{
return PotionUtils.appendEffects(PotionItems.getBottle(item, potion), listOf(PotionEffect(potion, duration?.baseTicks ?: 0, 0)))
}
val baseEffect
get() = PotionEffect(potion, duration?.baseTicks ?: 0, 0)
val vanillaOverrideStrongEffect
get() = PotionEffect(potion, duration?.getDuration(0, 1) ?: 0, 1)
val vanillaOverrideLongEffect
get() = PotionEffect(potion, duration?.getDuration(1, 0) ?: 0, 0)
class Duration(val baseTicks: Int, val stepTicks: Int, val maxSteps: Int){
fun calculate(steps: Int, amplifier: Int): Int{
var ticks = baseTicks + (stepTicks * steps)
private fun getBaseDuration(steps: Int): Int{
return baseTicks + (stepTicks * steps)
}
private fun mp(amplifier: Int): Double{
return if (amplifier == 0)
0.4
else
0.5
}
fun getDuration(steps: Int, amplifier: Int): Int{
var ticks = getBaseDuration(steps)
repeat(amplifier){
val mp = if (it == 0)
0.4
else
0.5
ticks = (ticks * mp).floorToInt()
ticks = (ticks * mp(it)).floorToInt()
}
return ticks
}
fun getSteps(duration: Int, amplifier: Int): Int{
var unrolled = duration.toDouble()
repeat(amplifier){
unrolled /= mp(it)
}
return (0..maxSteps).minBy { abs(getBaseDuration(it) - unrolled) } ?: 0
}
}
inner class Instance(private val stack: ItemStack, private val effect: PotionEffect){
private val durationSteps
get() = stack.heeTagOrNull?.getIntegerOrNull("DurationSteps") ?: 0
private val durationSteps = duration?.getSteps(effect.duration, amplifier) ?: 0
private val amplifier
get() = effect.amplifier
@ -63,21 +80,26 @@ class PotionTypeInfo(
val reversed = PotionBrewing.REVERSAL[potion] ?: return null
val info = PotionBrewing.INFO[reversed] ?: return null
val baseItem = info.getBasePotion(stack.item)
val baseEffect = PotionEffect(reversed, 0, 0, effect.isAmbient, effect.doesShowParticles())
if (durationSteps == 0 && amplifier == 0){
return PotionItems.getBottle(stack.item, potion, withBaseEffect = true)
}
return info.Instance(baseItem, baseEffect).createNewEffect(durationSteps, baseEffect.amplifier)
val newItem = PotionItems.getBottle(stack.item, potion, withBaseEffect = false)
val newEffect = PotionEffect(reversed, 0, 0, effect.isAmbient, effect.doesShowParticles())
return info.Instance(newItem, newEffect).createNewEffect(durationSteps, newEffect.amplifier)
}
private fun createNewEffect(durationSteps: Int, amplifier: Int): ItemStack{
val newDuration = duration?.calculate(durationSteps, amplifier) ?: 0
val newDuration = duration?.getDuration(durationSteps, amplifier) ?: 0
val newEffect = PotionEffect(potion, newDuration, amplifier, effect.isAmbient, effect.doesShowParticles())
val newStack = stack.copy()
newStack.heeTag.setInteger("DurationSteps", durationSteps)
newStack.nbt.removeTag(PotionItems.CUSTOM_EFFECTS_TAG)
return PotionUtils.appendEffects(newStack, listOf(newEffect))
return with(stack.copy()){
nbt.removeTag(PotionItems.CUSTOM_EFFECTS_TAG)
PotionUtils.addPotionToItemStack(this, PotionItems.findNoEffectOverride(PotionUtils.getPotionFromItem(this)))
PotionUtils.appendEffects(this, listOf(newEffect))
}
}
}
}

View File

@ -20,7 +20,9 @@ sealed class BrewBasicEffects(private val base: PotionType, private val registry
override fun brew(input: ItemStack, ingredient: ItemStack): ItemStack{
val entry = registry.entries.first { matchesReagent(ingredient, it.key) }
return PotionBrewing.INFO[entry.value]?.getBasePotion(input.item) ?: ItemStack.EMPTY
val info = PotionBrewing.INFO[entry.value] ?: return ItemStack.EMPTY
return PotionItems.getBottle(input.item, info.potion, withBaseEffect = true)
}
private fun matchesReagent(ingredient: ItemStack, key: Pair<Item, Int>): Boolean{

View File

@ -2,6 +2,7 @@ package chylex.hee.init
import chylex.hee.HEE
import chylex.hee.game.mechanics.potion.PotionLifeless
import chylex.hee.game.mechanics.potion.PotionPurity
import chylex.hee.game.mechanics.potion.brewing.PotionBrewing
import chylex.hee.game.mechanics.potion.brewing.PotionItems
import chylex.hee.game.mechanics.potion.brewing.recipes.BrewBasicEffects
import chylex.hee.game.mechanics.potion.brewing.recipes.BrewUnalteredPotions
@ -10,9 +11,9 @@ import chylex.hee.game.mechanics.potion.brewing.recipes.BrewWaterToMundane
import chylex.hee.game.mechanics.potion.brewing.recipes.BrewWaterToThick
import chylex.hee.game.mechanics.potion.brewing.recipes.ReinsertPotionItems
import chylex.hee.system.Resource
import chylex.hee.system.util.getIfExists
import com.google.common.collect.ImmutableList
import net.minecraft.potion.Potion
import net.minecraft.potion.PotionEffect
import net.minecraft.potion.PotionType
import net.minecraftforge.common.brewing.BrewingRecipeRegistry
import net.minecraftforge.common.brewing.IBrewingRecipe
@ -25,13 +26,56 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
object ModPotions{
@JvmStatic
@SubscribeEvent
fun onRegister(e: RegistryEvent.Register<Potion>){
fun onRegisterPotions(e: RegistryEvent.Register<Potion>){
with(e.registry){
register(PotionLifeless named "lifeless")
register(PotionPurity named "purity")
}
}
@JvmStatic
@SubscribeEvent
fun onRegisterTypes(e: RegistryEvent.Register<PotionType>){
with(e.registry){
val alteredTypes = PotionItems.ALTERED_TYPES.map { it.registryName!!.path }.toSet()
for(type in this){
val location = type.registryName!!
val domain = location.namespace
val path = location.path
if ((domain == Resource.Vanilla.domain || domain == Resource.Custom.domain) && alteredTypes.contains(path) && type.baseName == null && type.effects.isNotEmpty()){
val info = PotionBrewing.INFO[type.effects[0].potion]
if (info != null){
// custom brewing system uses NBT to apply duration/level modifiers
// to disable the original effect, each potion type is duplicated with no base effects
val override = PotionType(path) named "${path}_no_effect_override"
register(override) // TODO the duplicates still show up in creative menu etc
// change base effects for vanilla potions to avoid breaking creative menu and compatibility w/ original items
// register type overrides so that brewing recipes can convert them
type.effects = ImmutableList.of(info.baseEffect)
PotionItems.registerNoEffectOverride(type, override)
getIfExists(Resource.Vanilla("strong_$path"))?.let {
it.effects = ImmutableList.of(info.vanillaOverrideStrongEffect)
PotionItems.registerNoEffectOverride(it, override)
}
getIfExists(Resource.Vanilla("long_$path"))?.let {
it.effects = ImmutableList.of(info.vanillaOverrideLongEffect)
PotionItems.registerNoEffectOverride(it, override)
}
}
}
}
}
}
// Recipes
fun setupVanillaOverrides(){
@ -53,19 +97,6 @@ object ModPotions{
BrewUnalteredPotions
))
}
val vanillaTypes = PotionItems.VANILLA_TYPES.map { it.registryName!!.path }.toSet()
val emptyEffects = ImmutableList.of<PotionEffect>()
for(type in PotionType.REGISTRY){
val location = type.registryName!!
if (location.namespace == Resource.Vanilla.domain && (vanillaTypes.contains(location.path) || type.baseName?.let(vanillaTypes::contains) == true)){
type.effects = emptyEffects // removes duplicate effects when using custom effects in NBT
}
// TODO fix creative tab & tipped arrows, might be better to just ASM something
}
}
// Utilities
@ -74,4 +105,8 @@ object ModPotions{
setPotionName("effect.hee.$registryName")
setRegistryName(Resource.Custom(registryName))
}
private infix fun PotionType.named(registryName: String) = apply {
setRegistryName(Resource.Custom(registryName))
}
}