From ddf2c178e617e3835fb888465c0eb82597bb1124 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 26 Feb 2022 20:03:29 +0700 Subject: [PATCH] Revisit android features structure --- .../mc/otm/android/AndroidFeature.java | 80 ------------ .../mc/otm/android/AndroidFeatureType.java | 41 ------ .../android/feature/AndroidExtendedReach.java | 36 ------ .../feature/AndroidLimbOverclocking.java | 49 -------- .../android/feature/AndroidNanobotsArmor.java | 111 ---------------- .../feature/AndroidNanobotsRegeneration.java | 80 ------------ .../network/android/AndroidFeaturePacket.java | 7 +- .../mc/otm/android/AndroidFeature.kt | 76 +++++++++++ .../mc/otm/android/feature/ExtendedReach.kt | 32 +++++ .../otm/android/feature/LimbOverclocking.kt | 35 ++++++ .../mc/otm/android/feature/NanobotsArmor.kt | 89 +++++++++++++ .../android/feature/NanobotsRegeneration.kt | 71 +++++++++++ .../capability/android/AndroidCapability.kt | 118 ++++++++++-------- .../capability/android/IAndroidCapability.kt | 2 +- .../mc/otm/registry/AndroidFeatures.kt | 20 +-- .../mc/otm/registry/AndroidResearch.kt | 17 +-- 16 files changed, 388 insertions(+), 476 deletions(-) delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeatureType.java delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidExtendedReach.java delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidLimbOverclocking.java delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java delete mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ExtendedReach.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/LimbOverclocking.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmor.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsRegeneration.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java deleted file mode 100644 index 2f6de8335..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java +++ /dev/null @@ -1,80 +0,0 @@ -package ru.dbotthepony.mc.otm.android; - -import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; - -public class AndroidFeature implements INBTSerializable { - public final AndroidFeatureType type; - public final IAndroidCapability capability; - - protected int level = 0; - - public AndroidFeature(AndroidFeatureType type, IAndroidCapability capability) { - this.type = type; - this.capability = capability; - } - - public void setLevel(int level) { - if (this.level != level) { - this.level = level; - applyModifiers(); - } - } - - public int getLevel() { - return level; - } - - @Override - public boolean equals(Object obj) { - if (super.equals(obj)) - return true; - - if (obj instanceof AndroidFeature feature) - return feature.type.equals(type); - - return false; - } - - public void invalidateNetwork() { - // when player forgets everything - } - - @Override - public int hashCode() { - return type.hashCode(); - } - - public void tickClient() { - // override - } - - public void tickServer() { - // override - } - - public void applyModifiers() {} - public void removeModifiers() {} - - public void serializeNBT(CompoundTag tag) { - tag.putInt("level", level); - } - - public void onHurt(LivingHurtEvent event) { - // override - } - - @Override - public CompoundTag serializeNBT() { - var tag = new CompoundTag(); - serializeNBT(tag); - return tag; - } - - @Override - public void deserializeNBT(CompoundTag tag) { - level = tag.getInt("level"); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeatureType.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeatureType.java deleted file mode 100644 index c8e71c0f2..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeatureType.java +++ /dev/null @@ -1,41 +0,0 @@ -package ru.dbotthepony.mc.otm.android; - -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TranslatableComponent; -import net.minecraftforge.registries.*; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; - -public class AndroidFeatureType extends ForgeRegistryEntry> { - public interface AndroidFeatureFactory { - T factory(IAndroidCapability capability); - } - - public interface AndroidFullFeatureFactory { - T factory(AndroidFeatureType type, IAndroidCapability capability); - } - - protected final AndroidFeatureFactory factory; - - public AndroidFeatureType(AndroidFeatureFactory factory) { - this.factory = factory; - } - - public AndroidFeatureType(AndroidFullFeatureFactory factory) { - this.factory = (c) -> factory.factory(this, c); - } - - public T factory(IAndroidCapability capability) { - return factory.factory(capability); - } - - public boolean isApplicable(IAndroidCapability capability) { - return true; - } - - public Component getDisplayName() { - if (getRegistryName() == null) - return new TranslatableComponent("android_feature.null.null"); - - return new TranslatableComponent("android_feature." + getRegistryName().getNamespace() + "." + getRegistryName().getPath()); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidExtendedReach.java b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidExtendedReach.java deleted file mode 100644 index c214ab0c8..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidExtendedReach.java +++ /dev/null @@ -1,36 +0,0 @@ -package ru.dbotthepony.mc.otm.android.feature; - -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraftforge.common.ForgeMod; -import ru.dbotthepony.mc.otm.android.AndroidFeature; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; -import ru.dbotthepony.mc.otm.registry.AndroidFeatures; - -import java.util.UUID; - -public class AndroidExtendedReach extends AndroidFeature { - public static final UUID MODIFIER_ID = UUID.fromString("4a3fae46-47a8-a03f-857d-f5c2b2c8f2f2"); - - public AndroidExtendedReach(IAndroidCapability capability) { - super(AndroidFeatures.INSTANCE.getEXTENDED_REACH(), capability); - } - - @Override - public void applyModifiers() { - var reach = capability.getEntity().getAttribute(ForgeMod.REACH_DISTANCE.get()); - - if (reach != null) { - reach.removePermanentModifier(MODIFIER_ID); - reach.addPermanentModifier(new AttributeModifier(MODIFIER_ID, type.getDisplayName().toString(), level + 1, AttributeModifier.Operation.ADDITION)); - } - } - - @Override - public void removeModifiers() { - var reach = capability.getEntity().getAttribute(ForgeMod.REACH_DISTANCE.get()); - - if (reach != null) { - reach.removePermanentModifier(MODIFIER_ID); - } - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidLimbOverclocking.java b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidLimbOverclocking.java deleted file mode 100644 index 5f6da688c..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidLimbOverclocking.java +++ /dev/null @@ -1,49 +0,0 @@ -package ru.dbotthepony.mc.otm.android.feature; - -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import ru.dbotthepony.mc.otm.android.AndroidFeature; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; -import ru.dbotthepony.mc.otm.registry.AndroidFeatures; - -import java.util.UUID; - -public class AndroidLimbOverclocking extends AndroidFeature { - public static final UUID MODIFIER_ID = UUID.fromString("4a3fae46-e57b-4e20-857d-f5c2b2c8f2f2"); - - public AndroidLimbOverclocking(IAndroidCapability capability) { - super(AndroidFeatures.INSTANCE.getLIMB_OVERCLOCKING(), capability); - } - - @Override - public void applyModifiers() { - var speed = capability.getEntity().getAttribute(Attributes.MOVEMENT_SPEED); - - if (speed != null) { - speed.removePermanentModifier(MODIFIER_ID); - speed.addPermanentModifier(new AttributeModifier(MODIFIER_ID, type.getDisplayName().toString(), 0.08d * (level + 1), AttributeModifier.Operation.MULTIPLY_TOTAL)); - } - - var attack_speed = capability.getEntity().getAttribute(Attributes.ATTACK_SPEED); - - if (attack_speed != null) { - attack_speed.removePermanentModifier(MODIFIER_ID); - attack_speed.addPermanentModifier(new AttributeModifier(MODIFIER_ID, type.getDisplayName().toString(), 0.06d * (level + 1), AttributeModifier.Operation.MULTIPLY_TOTAL)); - } - } - - @Override - public void removeModifiers() { - var speed = capability.getEntity().getAttribute(Attributes.MOVEMENT_SPEED); - - if (speed != null) { - speed.removePermanentModifier(MODIFIER_ID); - } - - var attack_speed = capability.getEntity().getAttribute(Attributes.ATTACK_SPEED); - - if (attack_speed != null) { - attack_speed.removePermanentModifier(MODIFIER_ID); - } - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java deleted file mode 100644 index c8f079b3e..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java +++ /dev/null @@ -1,111 +0,0 @@ -package ru.dbotthepony.mc.otm.android.feature; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import ru.dbotthepony.mc.otm.android.AndroidFeature; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; -import ru.dbotthepony.mc.otm.registry.AndroidFeatures; -import ru.dbotthepony.mc.otm.registry.MNames; -import ru.dbotthepony.mc.otm.registry.StatNames; - -public class AndroidNanobotsArmor extends AndroidFeature { - public AndroidNanobotsArmor(IAndroidCapability capability) { - super(AndroidFeatures.INSTANCE.getNANOBOTS_ARMOR(), capability); - } - - public int getStrength() { - return strength; - } - - public void setStrength(int strength) { - this.strength = Math.max(0, Math.min(2, strength)); - } - - public int getSpeed() { - return speed; - } - - public void setSpeed(int speed) { - this.speed = Math.max(0, Math.min(2, speed)); - } - - protected int strength = 0; - protected int speed = 0; - - protected int ticks_passed = 0; - protected int layers = 0; - - protected static final ImpreciseFraction ENERGY_PER_BUILT = new ImpreciseFraction(200); - protected static final ImpreciseFraction ENERGY_PER_HITPOINT = new ImpreciseFraction(500); - - public static final int[] TICKS = new int[] { - 80, // 4 seconds to build a layer - 70, // 3.5 seconds to build a layer - 60, // 3 seconds to build a layer - 50, // 2.5 seconds to build a layer - }; - - public static final float[] SHIELD_STRENGTH = new float[] { - 0.1f, - 0.2f, - 0.3f, - 0.4f, - }; - - @Override - public void tickServer() { - if (layers < strength + 1 && capability.extractEnergyInner(ENERGY_PER_BUILT, true).compareTo(ENERGY_PER_BUILT) == 0) { - ticks_passed++; - - if (ticks_passed >= TICKS[speed]) { - layers++; - capability.extractEnergyInner(ENERGY_PER_BUILT, false); - } - } else { - ticks_passed = 0; - } - } - - @Override - public void onHurt(LivingHurtEvent event) { - ticks_passed = 0; - - if (!event.getSource().isBypassArmor() && layers > 0) { - var absorbed = event.getAmount() * SHIELD_STRENGTH[layers]; - - if (absorbed > 0.1f) { - var required = ENERGY_PER_HITPOINT.times(absorbed); - var extracted = capability.extractEnergyInner(required, false); - var real_absorbed = absorbed * extracted.div(required).toFloat(); - event.setAmount(event.getAmount() - real_absorbed); - - if (capability.getEntity() instanceof ServerPlayer ply) { - ply.awardStat(StatNames.INSTANCE.getDAMAGE_ABSORBED(), Math.round(real_absorbed * 10f)); - } - - layers--; - } - } - } - - @Override - public void serializeNBT(CompoundTag tag) { - super.serializeNBT(tag); - tag.putInt("ticks_passed", ticks_passed); - tag.putInt("layers", layers); - tag.putInt("strength", strength); - tag.putInt("speed", speed); - } - - @Override - public void deserializeNBT(CompoundTag tag) { - super.deserializeNBT(tag); - - ticks_passed = tag.getInt("ticks_passed"); - layers = tag.getInt("layers"); - strength = tag.getInt("strength"); - speed = tag.getInt("speed"); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java deleted file mode 100644 index ab704dcaa..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java +++ /dev/null @@ -1,80 +0,0 @@ -package ru.dbotthepony.mc.otm.android.feature; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import ru.dbotthepony.mc.otm.android.AndroidFeature; -import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; -import ru.dbotthepony.mc.otm.core.ImpreciseFraction; -import ru.dbotthepony.mc.otm.registry.AndroidFeatures; -import ru.dbotthepony.mc.otm.registry.MNames; -import ru.dbotthepony.mc.otm.registry.StatNames; - -public class AndroidNanobotsRegeneration extends AndroidFeature { - public AndroidNanobotsRegeneration(IAndroidCapability capability) { - super(AndroidFeatures.INSTANCE.getNANOBOTS_REGENERATION(), capability); - } - - protected int ticks_passed = 0; - protected int heal_ticks = 0; - - protected static final ImpreciseFraction ENERGY_PER_HITPOINT = new ImpreciseFraction(800); - - protected static final int[] TICKS_BETWEEN_HEAL = new int[] { - 100, // 5 seconds - 80, // 4 seconds - 60, // 3 seconds - 40, // 2 seconds - }; - - @Override - public void tickServer() { - var ent = capability.getEntity(); - - if (ent.getHealth() > 0 && ent.getHealth() < ent.getMaxHealth()) { - ticks_passed++; - - var wait_time = heal_ticks >= TICKS_BETWEEN_HEAL.length ? TICKS_BETWEEN_HEAL[TICKS_BETWEEN_HEAL.length - 1] : TICKS_BETWEEN_HEAL[heal_ticks]; - - if (ticks_passed > wait_time) { - var missing = Math.min(1, ent.getMaxHealth() - ent.getHealth()); - var extract = capability.extractEnergyInner(ENERGY_PER_HITPOINT.times(missing), false); - - if (extract.compareTo(ImpreciseFraction.ZERO) > 0) { - heal_ticks = Math.min(heal_ticks + 1, level); - var heal = missing * extract.div(ENERGY_PER_HITPOINT).toFloat(); - ent.heal(heal); - - if (capability.getEntity() instanceof ServerPlayer ply) { - ply.awardStat(StatNames.INSTANCE.getHEALTH_REGENERATED(), Math.round(heal * 10f)); - } - - ticks_passed = 0; - } - } - } else { - heal_ticks = 0; - ticks_passed = 0; - } - } - - @Override - public void onHurt(LivingHurtEvent event) { - heal_ticks = 0; - ticks_passed = 0; - } - - @Override - public void serializeNBT(CompoundTag tag) { - super.serializeNBT(tag); - tag.putInt("heal_ticks", heal_ticks); - tag.putInt("ticks_passed", ticks_passed); - } - - @Override - public void deserializeNBT(CompoundTag tag) { - super.deserializeNBT(tag); - heal_ticks = tag.getInt("heal_ticks"); - ticks_passed = tag.getInt("ticks_passed"); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java index 5b3bfd4f7..4ca835b86 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java @@ -15,13 +15,8 @@ import java.util.Objects; import java.util.function.Supplier; public record AndroidFeaturePacket(boolean is_added, AndroidFeatureType feature) { - public AndroidFeaturePacket(boolean is_added, AndroidFeatureType feature) { - this.is_added = is_added; - this.feature = feature; - } - public AndroidFeaturePacket(boolean is_added, AndroidFeature feature) { - this(is_added, feature.type); + this(is_added, feature.getType()); } public void write(FriendlyByteBuf buffer) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt new file mode 100644 index 000000000..1905cbdde --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt @@ -0,0 +1,76 @@ +package ru.dbotthepony.mc.otm.android + +import net.minecraft.nbt.CompoundTag +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.TranslatableComponent +import net.minecraftforge.common.util.INBTSerializable +import net.minecraftforge.event.entity.living.LivingHurtEvent +import net.minecraftforge.registries.ForgeRegistryEntry +import ru.dbotthepony.mc.otm.capability.android.AndroidCapability +import ru.dbotthepony.mc.otm.set + +open class AndroidFeatureType : ForgeRegistryEntry> { + private val factory: (AndroidFeatureType, AndroidCapability) -> T + + constructor(factory: (AndroidCapability) -> T) : super() { + this.factory = { _, capability -> factory.invoke(capability) } + } + + constructor(factory: (AndroidFeatureType, AndroidCapability) -> T) : super() { + this.factory = factory + } + + fun create(android: AndroidCapability): T { + return factory.invoke(this, android) + } + + open fun isApplicable(android: AndroidCapability) = true + + open val displayName: Component get() = registryName?.let { TranslatableComponent("android_feature.${it.namespace}.${it.path}") } ?: TranslatableComponent("android_feature.null.null") +} + +abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: AndroidCapability) : INBTSerializable { + val entity get() = android.entity + + open var level = 0 + set(value) { + if (value != field) { + field = value + applyModifiers() + } + } + + open fun tickClient() {} + open fun tickServer() {} + + /** + * Called when it is required to network everything again + */ + open fun invalidateNetwork() {} + + open fun applyModifiers() {} + open fun removeModifiers() {} + + open fun onHurt(event: LivingHurtEvent) {} + + override fun serializeNBT(): CompoundTag { + return CompoundTag().also { + it["level"] = level + } + } + + override fun deserializeNBT(nbt: CompoundTag) { + level = nbt.getInt("level") + } +} + +class DummyAndroidFeature(type: AndroidFeatureType<*>, android: AndroidCapability) : AndroidFeature(type, android) { + override fun serializeNBT(): CompoundTag { + return CompoundTag() + } + + override fun deserializeNBT(nbt: CompoundTag) { + + } +} + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ExtendedReach.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ExtendedReach.kt new file mode 100644 index 000000000..6d60727d6 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ExtendedReach.kt @@ -0,0 +1,32 @@ +package ru.dbotthepony.mc.otm.android.feature + +import net.minecraft.world.entity.ai.attributes.AttributeModifier +import net.minecraftforge.common.ForgeMod +import net.minecraftforge.event.entity.living.LivingHurtEvent +import ru.dbotthepony.mc.otm.android.AndroidFeature +import ru.dbotthepony.mc.otm.capability.android.AndroidCapability +import ru.dbotthepony.mc.otm.registry.AndroidFeatures +import java.util.* + +class ExtendedReach(android: AndroidCapability) : AndroidFeature(AndroidFeatures.EXTENDED_REACH, android) { + override fun applyModifiers() { + if (!ForgeMod.REACH_DISTANCE.isPresent) + return + + val reach = entity.getAttribute(ForgeMod.REACH_DISTANCE.get()) ?: return + + reach.removePermanentModifier(MODIFIER_ID) + reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), level + 1.0, AttributeModifier.Operation.ADDITION)) + } + + override fun removeModifiers() { + if (!ForgeMod.REACH_DISTANCE.isPresent) + return + + entity.getAttribute(ForgeMod.REACH_DISTANCE.get())?.removePermanentModifier(MODIFIER_ID) + } + + companion object { + private val MODIFIER_ID = UUID.fromString("4a3fae46-47a8-a03f-857d-f5c2b2c8f2f2") + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/LimbOverclocking.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/LimbOverclocking.kt new file mode 100644 index 000000000..813cf0728 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/LimbOverclocking.kt @@ -0,0 +1,35 @@ +package ru.dbotthepony.mc.otm.android.feature + +import net.minecraft.world.entity.ai.attributes.AttributeModifier +import net.minecraft.world.entity.ai.attributes.Attributes +import ru.dbotthepony.mc.otm.android.AndroidFeature +import ru.dbotthepony.mc.otm.capability.android.AndroidCapability +import ru.dbotthepony.mc.otm.registry.AndroidFeatures +import java.util.* + +class LimbOverclocking(android: AndroidCapability) : AndroidFeature(AndroidFeatures.LIMB_OVERCLOCKING, android) { + override fun applyModifiers() { + val speed = entity.getAttribute(Attributes.MOVEMENT_SPEED) + + if (speed != null) { + speed.removePermanentModifier(MODIFIER_ID) + speed.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.08, AttributeModifier.Operation.MULTIPLY_TOTAL)) + } + + val attackSpeed = entity.getAttribute(Attributes.ATTACK_SPEED) + + if (attackSpeed != null) { + attackSpeed.removePermanentModifier(MODIFIER_ID) + attackSpeed.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.06, AttributeModifier.Operation.MULTIPLY_TOTAL)) + } + } + + override fun removeModifiers() { + entity.getAttribute(Attributes.MOVEMENT_SPEED)?.removePermanentModifier(MODIFIER_ID) + entity.getAttribute(Attributes.ATTACK_SPEED)?.removePermanentModifier(MODIFIER_ID) + } + + companion object { + private val MODIFIER_ID = UUID.fromString("4a3fae46-e57b-4e20-857d-f5c2b2c8f2f2") + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmor.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmor.kt new file mode 100644 index 000000000..6b25cb923 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsArmor.kt @@ -0,0 +1,89 @@ +package ru.dbotthepony.mc.otm.android.feature + +import net.minecraft.nbt.CompoundTag +import net.minecraft.server.level.ServerPlayer +import net.minecraftforge.event.entity.living.LivingHurtEvent +import ru.dbotthepony.mc.otm.android.AndroidFeature +import ru.dbotthepony.mc.otm.capability.android.AndroidCapability +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.registry.AndroidFeatures +import ru.dbotthepony.mc.otm.registry.StatNames +import ru.dbotthepony.mc.otm.set +import kotlin.math.roundToInt + +class NanobotsArmor(android: AndroidCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_ARMOR, android) { + var strength: Int = 0 + set(value) { field = value.coerceIn(0 .. 2) } + + var speed: Int = 0 + set(value) { field = value.coerceIn(0 .. 2) } + + private var ticksPassed = 0 + private var layers = 0 + + override fun tickServer() { + if (layers < strength + 1 && android.extractEnergyInnerExact(ENERGY_PER_LAYER, true).isPositive) { + ticksPassed++ + + if (ticksPassed >= TICKS[speed]) { + layers++ + android.extractEnergyInner(ENERGY_PER_LAYER, false) + } + } else { + ticksPassed = 0 + } + } + + override fun onHurt(event: LivingHurtEvent) { + ticksPassed = 0 + + if (!event.source.isBypassArmor && layers > 0) { + val absorbed = event.amount * STRENGTH[layers] + + if (absorbed > 0.1f) { + val powerRequired = ENERGY_PER_HITPOINT * absorbed + val powerExtracted = android.extractEnergyInner(powerRequired, false) + val realAbsorbed = (powerExtracted / ENERGY_PER_HITPOINT).toFloat() + event.amount = event.amount - realAbsorbed + (entity as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt()) + layers-- + } + } + } + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["ticksPassed"] = ticksPassed + it["layers"] = layers + it["strength"] = strength + it["speed"] = speed + } + } + + override fun deserializeNBT(nbt: CompoundTag) { + super.deserializeNBT(nbt) + ticksPassed = nbt.getInt("ticksPassed") + layers = nbt.getInt("layers") + strength = nbt.getInt("strength") + speed = nbt.getInt("speed") + } + + companion object { + private val ENERGY_PER_LAYER = ImpreciseFraction(200) + private val ENERGY_PER_HITPOINT = ImpreciseFraction(500) + + private val TICKS = listOf( + 80, // 4 seconds to build a layer + 70, // 3.5 seconds to build a layer + 60, // 3 seconds to build a layer + 50, // 2.5 seconds to build a layer + ) + + private val STRENGTH = listOf( + 0.1f, + 0.2f, + 0.3f, + 0.4f, + ) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsRegeneration.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsRegeneration.kt new file mode 100644 index 000000000..17a02cb24 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/NanobotsRegeneration.kt @@ -0,0 +1,71 @@ +package ru.dbotthepony.mc.otm.android.feature + +import net.minecraft.nbt.CompoundTag +import net.minecraft.server.level.ServerPlayer +import net.minecraftforge.event.entity.living.LivingHurtEvent +import ru.dbotthepony.mc.otm.android.AndroidFeature +import ru.dbotthepony.mc.otm.capability.android.AndroidCapability +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.registry.AndroidFeatures +import ru.dbotthepony.mc.otm.registry.StatNames +import ru.dbotthepony.mc.otm.set +import kotlin.math.roundToInt + +class NanobotsRegeneration(android: AndroidCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_REGENERATION, android) { + private var ticksPassed = 0 + private var healTicks = 0 + + override fun tickServer() { + if (entity.health > 0f && entity.health < entity.maxHealth) { + ticksPassed++ + + val waitTime = TICKS_BETWEEN_HEAL.getOrElse(healTicks) { TICKS_BETWEEN_HEAL.last() } + + if (ticksPassed > waitTime) { + val missingHealth = entity.maxHealth - entity.health + val power = ENERGY_PER_HITPOINT * missingHealth + val extracted = android.extractEnergyInner(power, false) + + if (extracted.isPositive) { + healTicks = (healTicks + 1).coerceAtMost(level) + val healed = (extracted / ENERGY_PER_HITPOINT).toFloat() + entity.heal(healed) + (entity as ServerPlayer?)?.awardStat(StatNames.HEALTH_REGENERATED, (healed * 10f).roundToInt()) + ticksPassed = 0 + } + } + } else { + ticksPassed = 0 + healTicks = 0 + } + } + + override fun onHurt(event: LivingHurtEvent) { + ticksPassed = 0 + healTicks = 0 + } + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["ticksPassed"] = ticksPassed + it["healTicks"] = healTicks + } + } + + override fun deserializeNBT(nbt: CompoundTag) { + super.deserializeNBT(nbt) + ticksPassed = nbt.getInt("ticksPassed") + healTicks = nbt.getInt("healTicks") + } + + companion object { + private val ENERGY_PER_HITPOINT = ImpreciseFraction(800) + + private val TICKS_BETWEEN_HEAL = listOf( + 100, // 5 seconds + 80, // 4 seconds + 60, // 3 seconds + 40, // 2 seconds + ) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt index 718e1fb0d..314f58896 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt @@ -1,8 +1,8 @@ package ru.dbotthepony.mc.otm.capability.android -import net.minecraft.MethodsReturnNonnullByDefault +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import it.unimi.dsi.fastutil.objects.ObjectArraySet import net.minecraft.core.Direction -import javax.annotation.ParametersAreNonnullByDefault import net.minecraft.world.entity.LivingEntity import net.minecraftforge.common.capabilities.ICapabilityProvider import net.minecraftforge.common.util.INBTSerializable @@ -36,55 +36,55 @@ import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.ifHas -import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.StatNames import ru.dbotthepony.mc.otm.set import java.util.* -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapabilityProvider, IAndroidCapability, INBTSerializable { - @JvmField protected var battery = ImpreciseFraction.ZERO - @JvmField protected var maxBattery = ImpreciseFraction(60000) +open class AndroidCapability(final override val entity: LivingEntity) : ICapabilityProvider, IAndroidCapability, INBTSerializable { + protected var battery = ImpreciseFraction.ZERO + protected var maxBattery = ImpreciseFraction(60000) - override var batteryItemStack = ItemStack.EMPTY + override var batteryItemStack: ItemStack = ItemStack.EMPTY private var remoteBattery = ImpreciseFraction(-1) private var remoteMaxBattery = ImpreciseFraction(-1) private var remoteBatteryStack = ItemStack.EMPTY - @JvmField protected val features: MutableMap, AndroidFeature> = HashMap() - @JvmField protected val networkQueue = ArrayList() - @JvmField protected val queuedTicks = ArrayList() - @JvmField protected var networkFirst = false + protected val features = Object2ObjectArrayMap, AndroidFeature>() + protected val networkQueue = ArrayList() + protected val queuedTicks = ArrayList() + protected var networkTickedOnce = false protected fun addFeature(feature: AndroidFeature): Boolean { if (features.containsKey(feature.type)) return false features[feature.type] = feature - if (!ent.level.isClientSide) { - queuedTicks.add(Runnable { feature.applyModifiers() }) + if (!entity.level.isClientSide) { + queuedTicks.add(feature::applyModifiers) } - if (ent is ServerPlayer) { + + if (entity is ServerPlayer) { sendNetwork(AndroidFeaturePacket(true, feature)) } + return true } + @Suppress("unchecked_cast") override fun addFeature(feature: AndroidFeatureType): T { val get = features[feature] if (get != null) return get as T - val factory = feature.factory(this) + val factory = feature.create(this) features[feature] = factory - if (!ent.level.isClientSide) { - queuedTicks.add(Runnable { factory.applyModifiers() }) + if (!entity.level.isClientSide) { + queuedTicks.add(factory::applyModifiers) } - if (ent is ServerPlayer) { + if (entity is ServerPlayer) { sendNetwork(AndroidFeaturePacket(true, factory)) } @@ -95,11 +95,13 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab val removed = features.remove(feature) if (removed != null) { - if (!ent.level.isClientSide) { - queuedTicks.add { removed.removeModifiers() } + if (!entity.level.isClientSide) { + queuedTicks.add { + removed.removeModifiers() + } } - if (ent is ServerPlayer) { + if (entity is ServerPlayer) { sendNetwork(AndroidFeaturePacket(false, removed)) } } @@ -116,6 +118,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab return get.level >= level } + @Suppress("unchecked_cast") override fun getFeature(feature: AndroidFeatureType): T? { return features[feature] as T? } @@ -125,7 +128,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab remoteMaxBattery = ImpreciseFraction.MINUS_ONE remoteBatteryStack = ItemStack.EMPTY - if (ent is ServerPlayer) { + if (entity is ServerPlayer) { for (feature in features.values) { sendNetwork(AndroidFeaturePacket(true, feature)) feature.invalidateNetwork() @@ -157,8 +160,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab val featureList = ListTag() for (feature in features.values) { - val featureNbt = CompoundTag() - feature.serializeNBT(featureNbt) + val featureNbt = feature.serializeNBT() featureNbt["id"] = feature.type.registryName!!.toString() featureList.add(featureNbt) @@ -191,14 +193,14 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab if (tag is CompoundTag) { val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(tag.getString("id"))) - if (feature != null && feature.isApplicable(this)) { - val feature = feature.factory(this) + if (feature?.isApplicable(this) == true) { + val instance = feature.create(this) - feature.deserializeNBT(tag) - addFeature(feature) + instance.deserializeNBT(tag) + addFeature(instance) - if (!ent.level.isClientSide) { - queuedTicks.add(Runnable { feature.applyModifiers() }) + if (!entity.level.isClientSide) { + queuedTicks.add(instance::applyModifiers) } } } @@ -207,14 +209,14 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab fun dropBattery() { if (batteryItemStack.isEmpty) return - ent.spawnAtLocation(batteryItemStack) + entity.spawnAtLocation(batteryItemStack) batteryItemStack = ItemStack.EMPTY } protected fun sendNetwork(packet: Any) { - if (ent is ServerPlayer) { - if (networkFirst) { - MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { ent }, packet) + if (entity is ServerPlayer) { + if (networkTickedOnce) { + MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { entity }, packet) } else { networkQueue.add(packet) } @@ -222,9 +224,9 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab } protected open fun tickNetwork() { - networkFirst = true + networkTickedOnce = true - if (ent is ServerPlayer) { + if (entity is ServerPlayer) { if (battery != remoteBattery) { remoteBattery = battery sendNetwork(AndroidEnergyPacket(false, battery)) @@ -242,7 +244,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab if (networkQueue.size != 0) { for (packet in networkQueue) { - MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with {ent}, packet) + MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { entity }, packet) } networkQueue.clear() @@ -255,10 +257,15 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab override fun tickClient() { queuedTicks.clear() - if (!ent.isAlive) return + + if (!entity.isAlive) + return + tickInnerClientAlways() + if (isAndroid()) { tickInnerClient() + for (feature in features.values) { feature.tickClient() } @@ -266,17 +273,22 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab } override fun tick() { - if (!ent.isAlive) return + if (!entity.isAlive) return + tickServerAlways() + if (isAndroid()) { tickServer() + for (feature in features.values) { feature.tickServer() } } + for (runnable in queuedTicks) { runnable.run() } + queuedTicks.clear() tickNetwork() } @@ -284,12 +296,12 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab protected open fun tickServerAlways() {} protected open fun tickServer() { - if (ent.airSupply < ent.maxAirSupply) - ent.airSupply = ent.maxAirSupply + if (entity.airSupply < entity.maxAirSupply) + entity.airSupply = entity.maxAirSupply for (effect in UNAFFECTED_EFFECTS) - if (ent.hasEffect(effect)) - ent.removeEffect(effect) + if (entity.hasEffect(effect)) + entity.removeEffect(effect) if (!batteryItemStack.isEmpty && battery < maxBattery) { batteryItemStack.getCapability(CapabilityEnergy.ENERGY).ifPresent { @@ -325,8 +337,8 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab } if (howMuch.isZero) { - if (!simulate && ent is ServerPlayer) { - ent.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10) + if (!simulate && entity is ServerPlayer) { + entity.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10) } return drained @@ -339,8 +351,8 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab if (!simulate) { battery = new - if (ent is ServerPlayer) { - ent.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10) + if (entity is ServerPlayer) { + entity.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10) } } @@ -383,10 +395,6 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab return receiveEnergyOuter(howMuch, simulate) } - override fun getEntity(): LivingEntity { - return ent - } - override val batteryLevel: ImpreciseFraction get() { if (!batteryItemStack.isEmpty) { val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() @@ -434,10 +442,10 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab @Suppress("unused") companion object { @JvmField - val UNAFFECTED_EFFECTS: MutableSet = HashSet() + val UNAFFECTED_EFFECTS = ObjectArraySet() @JvmStatic - fun registerEffects(event: FMLCommonSetupEvent?) { + fun registerEffects(event: FMLCommonSetupEvent) { UNAFFECTED_EFFECTS.add(MobEffects.CONDUIT_POWER) UNAFFECTED_EFFECTS.add(MobEffects.HEAL) // maybe it makes things go haywire idk diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt index ddd72b899..e487c72ee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt @@ -14,7 +14,7 @@ import java.util.* interface IAndroidCapability : IMatteryEnergyStorage, INBTSerializable { fun tick() fun tickClient() - fun getEntity(): LivingEntity + val entity: LivingEntity fun addFeature(feature: AndroidFeatureType): T fun removeFeature(feature: AndroidFeatureType<*>): Boolean fun hasFeature(feature: AndroidFeatureType<*>): Boolean diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt index ba10c0feb..c83013a33 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidFeatures.kt @@ -4,20 +4,20 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext import net.minecraftforge.registries.DeferredRegister import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.android.AndroidFeatureType -import ru.dbotthepony.mc.otm.android.AndroidFeature -import ru.dbotthepony.mc.otm.android.feature.AndroidExtendedReach -import ru.dbotthepony.mc.otm.android.feature.AndroidLimbOverclocking -import ru.dbotthepony.mc.otm.android.feature.AndroidNanobotsArmor -import ru.dbotthepony.mc.otm.android.feature.AndroidNanobotsRegeneration +import ru.dbotthepony.mc.otm.android.DummyAndroidFeature +import ru.dbotthepony.mc.otm.android.feature.ExtendedReach +import ru.dbotthepony.mc.otm.android.feature.LimbOverclocking +import ru.dbotthepony.mc.otm.android.feature.NanobotsArmor +import ru.dbotthepony.mc.otm.android.feature.NanobotsRegeneration object AndroidFeatures { private val registry = DeferredRegister.create(AndroidFeatureType::class.java, OverdriveThatMatters.MOD_ID) - val AIR_BAGS: AndroidFeatureType<*> by registry.register(MNames.AIR_BAGS) { AndroidFeatureType(::AndroidFeature) } - val LIMB_OVERCLOCKING: AndroidFeatureType<*> by registry.register(MNames.LIMB_OVERCLOCKING) { AndroidFeatureType(::AndroidLimbOverclocking) } - val NANOBOTS_REGENERATION: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::AndroidNanobotsRegeneration) } - val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::AndroidNanobotsArmor) } - val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::AndroidExtendedReach) } + val AIR_BAGS: AndroidFeatureType<*> by registry.register(MNames.AIR_BAGS) { AndroidFeatureType(::DummyAndroidFeature) } + val LIMB_OVERCLOCKING: AndroidFeatureType<*> by registry.register(MNames.LIMB_OVERCLOCKING) { AndroidFeatureType(::LimbOverclocking) } + val NANOBOTS_REGENERATION: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_REGENERATION) { AndroidFeatureType(::NanobotsRegeneration) } + val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmor) } + val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReach) } internal fun register() { registry.register(FMLJavaModLoadingContext.get().modEventBus) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidResearch.kt index 128117a51..ec868f300 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/AndroidResearch.kt @@ -1,3 +1,6 @@ + +@file:Suppress("unused") + package ru.dbotthepony.mc.otm.registry import net.minecraft.network.chat.TextComponent @@ -9,7 +12,7 @@ import net.minecraftforge.registries.RegistryObject import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.android.AndroidResearchBuilder import ru.dbotthepony.mc.otm.android.AndroidResearchType -import ru.dbotthepony.mc.otm.android.feature.AndroidNanobotsArmor +import ru.dbotthepony.mc.otm.android.feature.NanobotsArmor import ru.dbotthepony.mc.otm.client.render.SkinElement object AndroidResearch { @@ -105,7 +108,7 @@ object AndroidResearch { registry.register(FMLJavaModLoadingContext.get().modEventBus) } - val AIR_BAGS by registry.register(MNames.AIR_BAGS) { + val AIR_BAGS: AndroidResearchType<*> by registry.register(MNames.AIR_BAGS) { AndroidResearchBuilder() .setExperienceCost(18) .addFeatureResult(AndroidFeatures.AIR_BAGS) @@ -114,7 +117,7 @@ object AndroidResearch { .build() } - val EXTENDED_REACH by registry.register(MNames.EXTENDED_REACH) { + val EXTENDED_REACH: AndroidResearchType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidResearchBuilder() .setExperienceCost(40) .addFeatureResult(AndroidFeatures.EXTENDED_REACH) @@ -123,7 +126,7 @@ object AndroidResearch { .build() } - val NANOBOTS by registry.register(MNames.NANOBOTS) { + val NANOBOTS: AndroidResearchType<*> by registry.register(MNames.NANOBOTS) { AndroidResearchBuilder() .setExperienceCost(15) .withDescription() @@ -131,7 +134,7 @@ object AndroidResearch { .build() } - val NANOBOTS_ARMOR by registry.register(MNames.NANOBOTS_ARMOR) { + val NANOBOTS_ARMOR: AndroidResearchType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidResearchBuilder() .setExperienceCost(25) .withDescription() @@ -222,7 +225,7 @@ object AndroidResearch { ) ) .addFeatureResult(OverdriveThatMatters.loc(MNames.NANOBOTS_ARMOR), 0) { feature -> - if ((feature as AndroidNanobotsArmor).strength < level) feature.strength = level + if ((feature as NanobotsArmor).strength < level) feature.strength = level } .build() }) @@ -247,7 +250,7 @@ object AndroidResearch { ) ) .addFeatureResult(OverdriveThatMatters.loc(MNames.NANOBOTS_ARMOR), 0) { feature -> - if ((feature as AndroidNanobotsArmor).speed < level) feature.speed = level + if ((feature as NanobotsArmor).speed < level) feature.speed = level } .build() })