Energy Sword

Fixes #17
This commit is contained in:
DBotThePony 2022-02-23 14:52:33 +07:00
parent cdb72a610b
commit f5d17f6bdb
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 395 additions and 7 deletions

View File

@ -102,6 +102,8 @@ public class MItems {
TRITANIUM_HOE
};
public static final EnergySwordItem ENERGY_SWORD = new EnergySwordItem();
public static final ItemTritaniumArmor TRITANIUM_HELMET = new ItemTritaniumArmor(EquipmentSlot.HEAD);
public static final ItemTritaniumArmor TRITANIUM_CHESTPLATE = new ItemTritaniumArmor(EquipmentSlot.CHEST);
public static final ItemTritaniumArmor TRITANIUM_PANTS = new ItemTritaniumArmor(EquipmentSlot.LEGS);
@ -297,6 +299,8 @@ public class MItems {
TRITANIUM_CHESTPLATE.setRegistryName(MNames.TRITANIUM_CHESTPLATE);
TRITANIUM_PANTS.setRegistryName(MNames.TRITANIUM_PANTS);
TRITANIUM_BOOTS.setRegistryName(MNames.TRITANIUM_BOOTS);
ENERGY_SWORD.setRegistryName(MNames.ENERGY_SWORD);
}
@SubscribeEvent
@ -402,6 +406,8 @@ public class MItems {
event.getRegistry().register(TRITANIUM_PANTS);
event.getRegistry().register(TRITANIUM_BOOTS);
event.getRegistry().register(ENERGY_SWORD);
// OverdriveThatMatters.LOGGER.info("Registered items");
}
}

View File

@ -92,6 +92,8 @@ public class MNames {
public static final ResourceLocation TRITANIUM_SHOVEL = loc("tritanium_shovel");
public static final ResourceLocation TRITANIUM_HOE = loc("tritanium_hoe");
public static final ResourceLocation ENERGY_SWORD = loc("energy_sword");
// items: crafting components
public static final ResourceLocation TRITANIUM_INGOT = loc("tritanium_ingot");

View File

@ -53,11 +53,14 @@ public class Registry {
public static final DamageSource DAMAGE_BECOME_HUMANE = new DamageSource("otm_become_humane");
public static final DamageSource DAMAGE_EVENT_HORIZON = new DamageSource("otm_event_horizon");
public static final DamageSource DAMAGE_HAWKING_RADIATION = new DamageSource("otm_hawking_radiation");
public static final String DAMAGE_EMP_NAME = "otm_emp";
public static final DamageSource DAMAGE_EMP = new EMPDamageSource();
static {
DAMAGE_BECOME_ANDROID.bypassArmor().bypassInvul().bypassMagic();
DAMAGE_BECOME_HUMANE.bypassArmor().bypassInvul().bypassMagic();
DAMAGE_EVENT_HORIZON.bypassMagic().bypassArmor();
DAMAGE_EMP.bypassMagic().bypassArmor();
// DAMAGE_HAWKING_RADIATION.bypassMagic().bypassArmor();
}

View File

@ -10,9 +10,12 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.world.Container
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.function.Consumer
operator fun Direction.unaryMinus(): Direction = this.opposite
@ -68,3 +71,22 @@ fun <T> LazyOptional<T>.orNull(): T? {
return resolve().orElse(null)
}
fun <T> LazyOptional<T>.orThrow(): T {
if (!isPresent) {
throw IllegalStateException("Capability was expected to be not null")
}
return resolve().orElse(null) ?: throw IllegalStateException("Capability was expected to be not null")
}
inline fun <T> LazyOptional<T>.ifPresentK(lambda: (T) -> Unit) {
if (isPresent) {
val value = resolve().orElse(null) ?: throw IllegalStateException("Capability was expected to be not null")
lambda.invoke(value)
}
}
val ItemStack.energy get() = getCapability(CapabilityEnergy.ENERGY).orNull()
val ItemStack.matteryEnergy get() = getCapability(MatteryCapability.ENERGY).orNull()
val LivingEntity.android get() = getCapability(MatteryCapability.ANDROID).orNull()

View File

@ -6,20 +6,93 @@ import ru.dbotthepony.mc.otm.core.ImpreciseFraction
// IEnergyStorage for direct compat with Forge Energy
interface IMatteryEnergyStorage : IEnergyStorage {
// such as cables. This is something that would work only with energy storage
/**
* such as cables. This is something that would work only with energy storage
*/
fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
// for internal needs, e.g. for work
// CAN also be used by something that does evil
// e.g. sucking out energy anomaly should use this
/**
* All or nothing
*/
fun extractEnergyOuterExact(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
val extracted = extractEnergyOuter(howMuch, true)
if (extracted != howMuch) {
return ImpreciseFraction.ZERO
}
if (!simulate) {
extractEnergyOuter(howMuch, false)
}
return extracted
}
/**
* for internal needs, e.g. for work
* CAN also be used by something that does evil
* e.g. sucking out energy anomaly should use this
*/
fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
// energy is received from outside, e.g. cables
/**
* All or nothing
*/
fun extractEnergyInnerExact(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
val extracted = extractEnergyInner(howMuch, true)
if (extracted != howMuch) {
return ImpreciseFraction.ZERO
}
if (!simulate) {
extractEnergyInner(howMuch, false)
}
return extracted
}
/**
* For energy receiving from outside, e.g. cables
*/
fun receiveEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
// energy is received from inside, e.g. generator generates power
fun receiveEnergyOuterExact(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
val extracted = receiveEnergyOuter(howMuch, true)
if (extracted != howMuch) {
return ImpreciseFraction.ZERO
}
if (!simulate) {
receiveEnergyOuter(howMuch, false)
}
return extracted
}
/**
* For energy receiving from inside, e.g. generator generates power
*/
fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction
/**
* All or nothing
*/
fun receiveEnergyInnerExact(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
val extracted = receiveEnergyInner(howMuch, true)
if (extracted != howMuch) {
return ImpreciseFraction.ZERO
}
if (!simulate) {
receiveEnergyInner(howMuch, false)
}
return extracted
}
fun extractEnergyOuter(howMuch: Long, simulate: Boolean): ImpreciseFraction {
return extractEnergyOuter(ImpreciseFraction(howMuch), simulate)
}

View File

@ -306,6 +306,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab
}
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@Suppress("name_shadowing")
var howMuch = howMuch
var drained = ImpreciseFraction.ZERO

View File

@ -19,6 +19,7 @@ import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifPresentK
class BatteryItem : Item {
private inner class BatteryMatteryCapability(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider {
@ -30,6 +31,7 @@ class BatteryItem : Item {
}
private fun energy(value: ImpreciseFraction) {
@Suppress("UsePropertyAccessSyntax")
stack.getOrCreateTag().put("otm_energy", value.serializeNBT())
}
@ -131,7 +133,7 @@ class BatteryItem : Item {
p_41423_.add(INFINITE_STORAGE)
p_41423_.add(throughputText)
} else {
stack.getCapability(MatteryCapability.ENERGY).ifPresent {
stack.getCapability(MatteryCapability.ENERGY).ifPresentK {
p_41423_.add(
TranslatableComponent(
"otm.item.power.normal.storage",
@ -140,6 +142,7 @@ class BatteryItem : Item {
).withStyle(ChatFormatting.GRAY)
)
}
p_41423_.add(throughputText)
}
}

View File

@ -0,0 +1,234 @@
package ru.dbotthepony.mc.otm.item
import com.google.common.collect.ImmutableMultimap
import com.google.common.collect.Multimap
import net.minecraft.ChatFormatting
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.Attribute
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.Material
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy
import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.menu.FormattingHelper
import ru.dbotthepony.mc.otm.registry.EMPDamageSource
class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) {
private inner class Energy(private val itemStack: ItemStack) : ICapabilityProvider, IMatteryEnergyStorage {
private val resolver = LazyOptional.of { this }
override fun <T : Any?> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (cap == CapabilityEnergy.ENERGY || cap == MatteryCapability.ENERGY) {
return resolver.cast()
}
return LazyOptional.empty()
}
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return ImpreciseFraction.ZERO
}
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (!howMuch.isPositive) {
return ImpreciseFraction.ZERO
}
val batteryLevel = batteryLevel
val newValue = (batteryLevel - howMuch).moreThanZero()
if (newValue == batteryLevel) {
return ImpreciseFraction.ZERO
}
val diff = batteryLevel - newValue
if (!simulate) {
energy(newValue)
}
return diff
}
override fun receiveEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return receiveEnergyInner(howMuch, simulate)
}
override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (!howMuch.isPositive) {
return ImpreciseFraction.ZERO
}
val batteryLevel = batteryLevel
val newValue = (batteryLevel + howMuch).min(maxBatteryLevel)
if (newValue == batteryLevel) {
return ImpreciseFraction.ZERO
}
val diff = newValue - batteryLevel
if (!simulate) {
energy(newValue)
}
return diff
}
private fun energy(value: ImpreciseFraction) {
@Suppress("UsePropertyAccessSyntax")
itemStack.getOrCreateTag().put("energy", value.serializeNBT())
}
override val batteryLevel: ImpreciseFraction
get() = itemStack.tag?.get("energy")?.let { ImpreciseFraction.deserializeNBT(it) } ?: ImpreciseFraction.ZERO
override val maxBatteryLevel: ImpreciseFraction
get() = MAX_ENERGY
}
val chargedAttributes: Multimap<Attribute, AttributeModifier>
val dischargedAttributes: Multimap<Attribute, AttributeModifier>
init {
var builder = ImmutableMultimap.builder<Attribute, AttributeModifier>()
builder.put(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", 13.0, AttributeModifier.Operation.ADDITION))
builder.put(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_UUID, "Weapon modifier", -2.4, AttributeModifier.Operation.ADDITION))
chargedAttributes = builder.build()
builder = ImmutableMultimap.builder()
builder.put(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", 3.5, AttributeModifier.Operation.ADDITION))
builder.put(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_UUID, "Weapon modifier", -2.4, AttributeModifier.Operation.ADDITION))
dischargedAttributes = builder.build()
}
override fun getDestroySpeed(itemStack: ItemStack, blockState: BlockState): Float {
val energy = itemStack.matteryEnergy ?: return 1f
if (blockState.`is`(Blocks.COBWEB)) {
if (energy.batteryLevel < COBWEB_POWER_COST) {
return 2f
} else {
return 25f
}
}
return when (blockState.material) {
Material.PLANT, Material.REPLACEABLE_PLANT, Material.VEGETABLE -> if (energy.batteryLevel < PLANT_POWER_COST) 1.5f else 4f
Material.LEAVES -> if (energy.batteryLevel < PLANT_POWER_COST) 1.5f else 8f
else -> 1f
}
}
override fun hurtEnemy(itemStack: ItemStack, victim: LivingEntity, attacker: LivingEntity): Boolean {
itemStack.matteryEnergy?.let {
if (!it.extractEnergyInnerExact(ENERGY_PER_SWING, false).isZero) {
victim.android?.let {
it.extractEnergyInner(ENERGY_ZAP, false)
victim.hurt(EMPDamageSource(attacker), 8f)
}
}
}
return true
}
override fun appendHoverText(
itemStack: ItemStack,
p_41422_: Level?,
p_41423_: MutableList<Component>,
p_41424_: TooltipFlag
) {
super.appendHoverText(itemStack, p_41422_, p_41423_, p_41424_)
itemStack.getCapability(MatteryCapability.ENERGY).ifPresentK {
p_41423_.add(
TranslatableComponent(
"otm.item.power.normal.storage",
FormattingHelper.formatPower(it.batteryLevel),
FormattingHelper.formatPower(it.maxBatteryLevel)
).withStyle(ChatFormatting.GRAY)
)
}
p_41423_.add(DESCRIPTION)
p_41423_.add(DESCRIPTION2)
}
override fun mineBlock(
itemStack: ItemStack,
p_41417_: Level,
blockState: BlockState,
p_41419_: BlockPos,
p_41420_: LivingEntity
): Boolean {
if (blockState.getDestroySpeed(p_41417_, p_41419_) != 0f) {
val energy = itemStack.matteryEnergy
when (blockState.material) {
Material.PLANT, Material.REPLACEABLE_PLANT, Material.VEGETABLE, Material.LEAVES ->
energy?.extractEnergyInnerExact(PLANT_POWER_COST, false)
}
if (blockState.`is`(Blocks.COBWEB)) {
energy?.extractEnergyInnerExact(COBWEB_POWER_COST, false)
}
}
return true
}
override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider {
return Energy(stack)
}
override fun getAttributeModifiers(
slot: EquipmentSlot,
itemStack: ItemStack
): Multimap<Attribute, AttributeModifier> {
if (slot != EquipmentSlot.MAINHAND) {
return ImmutableMultimap.of()
}
val energy = itemStack.matteryEnergy
if (energy != null && energy.batteryLevel >= ENERGY_PER_SWING) {
return chargedAttributes
}
return dischargedAttributes
}
companion object {
private val MAX_ENERGY = ImpreciseFraction(400_000)
private val ENERGY_ZAP = ImpreciseFraction(10_000)
private val ENERGY_PER_SWING = ImpreciseFraction(4_000)
private val COBWEB_POWER_COST = ImpreciseFraction(1_500)
private val PLANT_POWER_COST = ImpreciseFraction(500)
private val DESCRIPTION = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc").withStyle(ChatFormatting.DARK_GRAY)
private val DESCRIPTION2 = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc2").withStyle(ChatFormatting.DARK_GRAY)
}
}

View File

@ -0,0 +1,37 @@
package ru.dbotthepony.mc.otm.registry
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
class EMPDamageSource(private val entity: Entity? = null) : DamageSource(Registry.DAMAGE_EMP_NAME) {
init {
bypassArmor()
bypassMagic()
}
override fun scalesWithDifficulty(): Boolean {
return false
}
override fun getLocalizedDeathMessage(victim: LivingEntity): Component {
val itemStack = (entity as LivingEntity?)?.mainHandItem ?: ItemStack.EMPTY
if (!itemStack.isEmpty && itemStack.hasCustomHoverName()) {
return TranslatableComponent("death.attack.otm_emp.player.item", victim.displayName, entity!!.displayName, itemStack.displayName)
}
if (entity != null) {
return TranslatableComponent("death.attack.otm_emp.player", victim.displayName, entity.displayName)
}
return TranslatableComponent("death.attack.otm_emp", victim.displayName)
}
override fun getEntity(): Entity? {
return entity
}
}

View File

@ -168,11 +168,14 @@
"death.attack.otm_become_humane": "%1$s regained their humanity",
"death.attack.otm_event_horizon": "%1$s never crossed event horizon",
"death.attack.otm_hawking_radiation": "%1$s discovered Hawking radiation",
"death.attack.otm_emp": "%1$s electronics' fried",
"death.attack.otm_become_android.player": "%1$s lost their humanity whilst %2$s tried to reason with them",
"death.attack.otm_become_humane.player": "%1$s gained their humanity whilst %2$s tried to reason with them",
"death.attack.otm_event_horizon.player": "%1$s tried to cross event horizon whilst trying to escape %2$s",
"death.attack.otm_hawking_radiation.player": "%1$s disintegrated whilst fighting %2$s",
"death.attack.otm_emp.player": "%1$s blew fuzes of %2$s",
"death.attack.otm_emp.player.item": "%1$s blew fuzes of %2$s using %3$s",
"block.overdrive_that_matters.android_station": "Android Station",
"block.overdrive_that_matters.battery_bank": "Battery Bank",
@ -260,6 +263,10 @@
"item.overdrive_that_matters.battery_capacitor": "Capacitor Battery",
"item.overdrive_that_matters.battery_creative": "Creative Battery",
"item.overdrive_that_matters.energy_sword": "Powered Cake Slicer",
"item.overdrive_that_matters.energy_sword.desc": "Needs power to operate",
"item.overdrive_that_matters.energy_sword.desc2": "Deals extra damage to androids when powered",
"item.overdrive_that_matters.tritanium_sword": "Tritanium Sword",
"item.overdrive_that_matters.tritanium_pickaxe": "Tritanium Pickaxe",
"item.overdrive_that_matters.tritanium_shovel": "Tritanium Shovel",