From 7c5bfb1b36c5dc8acebfd698de8a5ba75be73385 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 24 Aug 2021 18:14:53 +0700 Subject: [PATCH] Nanobots, Regeneration and Armor features and research --- .../java/ru/dbotthepony/mc/otm/Registry.java | 148 +++++++++++++++++- .../mc/otm/android/AndroidFeature.java | 9 +- .../otm/android/AndroidResearchBuilder.java | 48 +++++- .../android/feature/AndroidNanobotsArmor.java | 105 +++++++++++++ .../feature/AndroidNanobotsRegeneration.java | 73 +++++++++ .../mc/otm/capability/AndroidCapability.java | 25 ++- .../capability/AndroidCapabilityPlayer.java | 8 +- .../mc/otm/capability/IAndroidCapability.java | 8 +- .../mc/otm/screen/AndroidStationScreen.java | 4 +- .../overdrive_that_matters/lang/en_us.json | 21 ++- 10 files changed, 415 insertions(+), 34 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index dbc0380d5..09e61bb4c 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -20,6 +20,8 @@ import ru.dbotthepony.mc.otm.android.AndroidFeature; import ru.dbotthepony.mc.otm.android.AndroidResearchBuilder; import ru.dbotthepony.mc.otm.android.AndroidResearchType; 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.block.*; import ru.dbotthepony.mc.otm.block.entity.*; import ru.dbotthepony.mc.otm.android.AndroidFeatureType; @@ -109,6 +111,7 @@ public class Registry { // android features and research public static final ResourceLocation AIR_BAGS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "air_bags"); + public static final ResourceLocation LIMB_OVERCLOCKING = new ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking"); public static final ResourceLocation LIMB_OVERCLOCKING_1 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking_1"); public static final ResourceLocation LIMB_OVERCLOCKING_2 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking_2"); @@ -116,6 +119,40 @@ public class Registry { public static final ResourceLocation LIMB_OVERCLOCKING_4 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking_4"); public static final ResourceLocation[] LIMB_OVERCLOCKING_LIST = new ResourceLocation[] { LIMB_OVERCLOCKING_1, LIMB_OVERCLOCKING_2, LIMB_OVERCLOCKING_3, LIMB_OVERCLOCKING_4 }; + + public static final ResourceLocation NANOBOTS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots"); + public static final ResourceLocation NANOBOTS_REGENERATION = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_regeneration"); + public static final ResourceLocation NANOBOTS_REGENERATION_1 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_regeneration_1"); + public static final ResourceLocation NANOBOTS_REGENERATION_2 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_regeneration_2"); + public static final ResourceLocation NANOBOTS_REGENERATION_3 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_regeneration_3"); + public static final ResourceLocation NANOBOTS_REGENERATION_4 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_regeneration_4"); + + public static final ResourceLocation[] NANOBOTS_REGENERATION_LIST = new ResourceLocation[] { NANOBOTS_REGENERATION_1, NANOBOTS_REGENERATION_2, NANOBOTS_REGENERATION_3, NANOBOTS_REGENERATION_4 }; + + public static final ResourceLocation NANOBOTS_ARMOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor"); + + public static final ResourceLocation NANOBOTS_ARMOR_STRENGTH_1 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_strength_1"); + public static final ResourceLocation NANOBOTS_ARMOR_STRENGTH_2 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_strength_2"); + public static final ResourceLocation NANOBOTS_ARMOR_STRENGTH_3 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_strength_3"); + public static final ResourceLocation[] NANOBOTS_ARMOR_STRENGTH_LIST = new ResourceLocation[] { + NANOBOTS_ARMOR_STRENGTH_1, + NANOBOTS_ARMOR_STRENGTH_2, + NANOBOTS_ARMOR_STRENGTH_3, + }; + + public static final ResourceLocation NANOBOTS_ARMOR_SPEED_1 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_speed_1"); + public static final ResourceLocation NANOBOTS_ARMOR_SPEED_2 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_speed_2"); + public static final ResourceLocation NANOBOTS_ARMOR_SPEED_3 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nanobots_armor_speed_3"); + public static final ResourceLocation[] NANOBOTS_ARMOR_SPEED_LIST = new ResourceLocation[] { + NANOBOTS_ARMOR_SPEED_1, + NANOBOTS_ARMOR_SPEED_2, + NANOBOTS_ARMOR_SPEED_3, + }; + + public static final ResourceLocation HYDRAULICS_OVERLOAD = new ResourceLocation(OverdriveThatMatters.MOD_ID, "hydraulics_overload"); + public static final ResourceLocation HYDRAULICS_OVERLOAD_1 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "hydraulics_overload_1"); + public static final ResourceLocation HYDRAULICS_OVERLOAD_2 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "hydraulics_overload_2"); + public static final ResourceLocation HYDRAULICS_OVERLOAD_3 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "hydraulics_overload_3"); } public static class Blocks { @@ -299,16 +336,22 @@ public class Registry { public static class AndroidFeatures { public static final AndroidFeatureType AIR_BAGS = new AndroidFeatureType<>(AndroidFeature::new); public static final AndroidFeatureType LIMB_OVERCLOCKING = new AndroidFeatureType<>(AndroidLimbOverclocking::new); + public static final AndroidFeatureType NANOBOTS_REGENERATION = new AndroidFeatureType<>(AndroidNanobotsRegeneration::new); + public static final AndroidFeatureType NANOBOTS_ARMOR = new AndroidFeatureType<>(AndroidNanobotsArmor::new); static { AIR_BAGS.setRegistryName(Names.AIR_BAGS); LIMB_OVERCLOCKING.setRegistryName(Names.LIMB_OVERCLOCKING); + NANOBOTS_REGENERATION.setRegistryName(Names.NANOBOTS_REGENERATION); + NANOBOTS_ARMOR.setRegistryName(Names.NANOBOTS_ARMOR); } @SubscribeEvent public static void register(final RegistryEvent.Register> event) { event.getRegistry().register(AIR_BAGS); event.getRegistry().register(LIMB_OVERCLOCKING); + event.getRegistry().register(NANOBOTS_REGENERATION); + event.getRegistry().register(NANOBOTS_ARMOR); } } @@ -326,7 +369,7 @@ public class Registry { public static final SkinElement ICON_ARC; public static final SkinElement ICON_ARROW; public static final SkinElement ICON_ARMOR; - public static final SkinElement ICON_REGENERATIVE; + public static final SkinElement ICON_NANOBOTS; public static final SkinElement ICON_NIGHT_VISION; public static final SkinElement ICON_OXYGEN_SUPPLY; @@ -357,7 +400,7 @@ public class Registry { ICON_ARC = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; ICON_ARROW = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; ICON_ARMOR = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; - ICON_REGENERATIVE = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; + ICON_NANOBOTS = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; ICON_NIGHT_VISION = new SkinElement(ICONS, x, y, 18, 18, 126, 126); x += 18; ICON_OXYGEN_SUPPLY = new SkinElement(ICONS, x, y, 18, 18, 126, 126); @@ -382,40 +425,131 @@ public class Registry { .build(); public static final AndroidResearchType[] LIMB_OVERCLOCKING = new AndroidResearchType[4]; + public static final AndroidResearchType[] NANOBOTS_REGENERATION = new AndroidResearchType[4]; + public static final AndroidResearchType[] NANOBOTS_ARMOR_STRENGTH = new AndroidResearchType[3]; + public static final AndroidResearchType[] NANOBOTS_ARMOR_SPEED = new AndroidResearchType[3]; + + public static final AndroidResearchType NANOBOTS = + new AndroidResearchBuilder() + .setExperienceCost(15) + .withDescription() + .withIcon(ICON_NANOBOTS) + .build(); + + public static final AndroidResearchType NANOBOTS_ARMOR = + new AndroidResearchBuilder() + .setExperienceCost(25) + .withDescription() + .addPrerequisite(Names.NANOBOTS) + .addFeatureResult(Names.NANOBOTS_ARMOR) + .withIcon(ICON_ARMOR) + .build(); static { AIR_BAGS.setRegistryName(Names.AIR_BAGS); + NANOBOTS.setRegistryName(Names.NANOBOTS); + NANOBOTS_ARMOR.setRegistryName(Names.NANOBOTS_ARMOR); for (int i = 0; i < 4; i++) { - var builder = new AndroidResearchBuilder() - .withDescription() - .setExperienceCost(24 + i * 8) + var limbs = new AndroidResearchBuilder() + .setExperienceCost(18 + i * 8) .withIconText(new TextComponent(String.valueOf(i + 1))) .withIcon(ICON_LIMB_OVERCLOCKING) .withName(new TranslatableComponent("android_research.overdrive_that_matters.limb_overclocking", i + 1)) .withDescription(new TranslatableComponent("android_research.overdrive_that_matters.limb_overclocking.description", (i + 1) * 8, (i + 1) * 6)) .addFeatureResult(Names.LIMB_OVERCLOCKING, i); + var regeneration = new AndroidResearchBuilder() + .setExperienceCost(20 + i * 6) + .withIconText(new TextComponent(String.valueOf(i + 1))) + .withIcon(ICON_NANOBOTS) + .withName(new TranslatableComponent("android_research.overdrive_that_matters.nanobots_regeneration", i + 1)) + .withDescription( + i > 0 ? new TranslatableComponent("android_research.overdrive_that_matters.nanobots_regeneration.description_improve") : new TranslatableComponent("android_research.overdrive_that_matters.nanobots_regeneration.description")) + .addFeatureResult(Names.NANOBOTS_REGENERATION, i); + if (i > 0) { - builder.addPrerequisite(Names.LIMB_OVERCLOCKING_LIST[i - 1]); + limbs.addPrerequisite(Names.LIMB_OVERCLOCKING_LIST[i - 1]); + regeneration.addPrerequisite(Names.NANOBOTS_REGENERATION_LIST[i - 1]); + } else { + regeneration.addPrerequisite(Names.NANOBOTS); } - LIMB_OVERCLOCKING[i] = builder.build(); + LIMB_OVERCLOCKING[i] = limbs.build(); + NANOBOTS_REGENERATION[i] = regeneration.build(); + } + + for (int i = 0; i < 3; i++) { + final int level = i + 1; + + NANOBOTS_ARMOR_STRENGTH[i] = new AndroidResearchBuilder() + .setExperienceCost(20 + i * 8) + .withIconText(new TextComponent(String.valueOf(i + 1))) + .withIcon(ICON_ARMOR) + .addPrerequisite(i > 0 ? Names.NANOBOTS_ARMOR_STRENGTH_LIST[i - 1] : Names.NANOBOTS_ARMOR) + .withName(new TranslatableComponent("android_research.overdrive_that_matters.nanobots_armor_strength", i + 1)) + .withDescription(new TranslatableComponent("android_research.overdrive_that_matters.nanobots_armor_strength.description", (i + 1) * 8, (i + 1) * 6)) + .addFeatureResult(Names.NANOBOTS_ARMOR, 0, (feature) -> { + if (((AndroidNanobotsArmor) feature).getStrength() < level) + ((AndroidNanobotsArmor) feature).setStrength(level); + }) + .build(); + + NANOBOTS_ARMOR_SPEED[i] = new AndroidResearchBuilder() + .setExperienceCost(20 + i * 8) + .withIconText(new TextComponent(String.valueOf(i + 1))) + .withIcon(ICON_ARMOR) + .addPrerequisite(i > 0 ? Names.NANOBOTS_ARMOR_SPEED_LIST[i - 1] : Names.NANOBOTS_ARMOR) + .withName(new TranslatableComponent("android_research.overdrive_that_matters.nanobots_armor_speed", i + 1)) + .withDescription(new TranslatableComponent("android_research.overdrive_that_matters.nanobots_armor_speed.description", (i + 1) * 8, (i + 1) * 6)) + .addFeatureResult(Names.NANOBOTS_ARMOR, 0, (feature) -> { + if (((AndroidNanobotsArmor) feature).getSpeed() < level) + ((AndroidNanobotsArmor) feature).setSpeed(level); + }) + .build(); } LIMB_OVERCLOCKING[0].setRegistryName(Names.LIMB_OVERCLOCKING_1); LIMB_OVERCLOCKING[1].setRegistryName(Names.LIMB_OVERCLOCKING_2); LIMB_OVERCLOCKING[2].setRegistryName(Names.LIMB_OVERCLOCKING_3); LIMB_OVERCLOCKING[3].setRegistryName(Names.LIMB_OVERCLOCKING_4); + + NANOBOTS_ARMOR_SPEED[0].setRegistryName(Names.NANOBOTS_ARMOR_SPEED_1); + NANOBOTS_ARMOR_SPEED[1].setRegistryName(Names.NANOBOTS_ARMOR_SPEED_2); + NANOBOTS_ARMOR_SPEED[2].setRegistryName(Names.NANOBOTS_ARMOR_SPEED_3); + + NANOBOTS_ARMOR_STRENGTH[0].setRegistryName(Names.NANOBOTS_ARMOR_STRENGTH_1); + NANOBOTS_ARMOR_STRENGTH[1].setRegistryName(Names.NANOBOTS_ARMOR_STRENGTH_2); + NANOBOTS_ARMOR_STRENGTH[2].setRegistryName(Names.NANOBOTS_ARMOR_STRENGTH_3); + + NANOBOTS_REGENERATION[0].setRegistryName(Names.NANOBOTS_REGENERATION_1); + NANOBOTS_REGENERATION[1].setRegistryName(Names.NANOBOTS_REGENERATION_2); + NANOBOTS_REGENERATION[2].setRegistryName(Names.NANOBOTS_REGENERATION_3); + NANOBOTS_REGENERATION[3].setRegistryName(Names.NANOBOTS_REGENERATION_4); } @SubscribeEvent public static void register(final RegistryEvent.Register> event) { event.getRegistry().register(AIR_BAGS); + event.getRegistry().register(NANOBOTS); + event.getRegistry().register(NANOBOTS_ARMOR); + event.getRegistry().register(LIMB_OVERCLOCKING[0]); event.getRegistry().register(LIMB_OVERCLOCKING[1]); event.getRegistry().register(LIMB_OVERCLOCKING[2]); event.getRegistry().register(LIMB_OVERCLOCKING[3]); + + event.getRegistry().register(NANOBOTS_ARMOR_SPEED[0]); + event.getRegistry().register(NANOBOTS_ARMOR_SPEED[1]); + event.getRegistry().register(NANOBOTS_ARMOR_SPEED[2]); + event.getRegistry().register(NANOBOTS_ARMOR_STRENGTH[0]); + event.getRegistry().register(NANOBOTS_ARMOR_STRENGTH[1]); + event.getRegistry().register(NANOBOTS_ARMOR_STRENGTH[2]); + + event.getRegistry().register(NANOBOTS_REGENERATION[0]); + event.getRegistry().register(NANOBOTS_REGENERATION[1]); + event.getRegistry().register(NANOBOTS_REGENERATION[2]); + event.getRegistry().register(NANOBOTS_REGENERATION[3]); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java index 4490dba80..018378324 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java +++ b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidFeature.java @@ -2,6 +2,7 @@ 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.IAndroidCapability; public class AndroidFeature implements INBTSerializable { @@ -47,11 +48,11 @@ public class AndroidFeature implements INBTSerializable { } public void tickClient() { - + // override } public void tickServer() { - + // override } public void applyModifiers() {} @@ -61,6 +62,10 @@ public class AndroidFeature implements INBTSerializable { tag.putInt("level", level); } + public void onHurt(LivingHurtEvent event) { + // override + } + @Override public CompoundTag serializeNBT() { var tag = new CompoundTag(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java index 2465a92a0..8e84c6edf 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java +++ b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java @@ -15,19 +15,29 @@ import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; public class AndroidResearchBuilder { record DeferredItemStack(ResourceLocation id, int amount) { } - record DeferredFeature(ResourceLocation id, int level) { - DeferredFeature(ResourceLocation id, int level) { + record DeferredFeature(ResourceLocation id, int level, Consumer callback) { + DeferredFeature(ResourceLocation id, int level, Consumer callback) { this.id = id; this.level = level; + this.callback = callback; + } + + DeferredFeature(ResourceLocation id, int level) { + this(id, level, (f) -> {}); + } + + DeferredFeature(ResourceLocation id, Consumer callback) { + this(id, 0, (f) -> {}); } DeferredFeature(ResourceLocation id) { - this(id, 0); + this(id, 0, (f) -> {}); } } @@ -61,6 +71,16 @@ public class AndroidResearchBuilder { return this; } + public AndroidResearchBuilder addFeatureResult(ResourceLocation location, Consumer callback) { + feature_results.add(new DeferredFeature(location, callback)); + return this; + } + + public AndroidResearchBuilder addFeatureResult(AndroidFeatureType location, Consumer callback) { + feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()), callback)); + return this; + } + public AndroidResearchBuilder addFeatureResult(ResourceLocation location, int level) { feature_results.add(new DeferredFeature(location, level)); return this; @@ -71,6 +91,16 @@ public class AndroidResearchBuilder { return this; } + public AndroidResearchBuilder addFeatureResult(ResourceLocation location, int level, Consumer callback) { + feature_results.add(new DeferredFeature(location, level, callback)); + return this; + } + + public AndroidResearchBuilder addFeatureResult(AndroidFeatureType location, int level, Consumer callback) { + feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()), level, callback)); + return this; + } + public AndroidResearchBuilder addItem(ResourceLocation location) { items.add(new DeferredItemStack(location, 1)); return this; @@ -115,7 +145,7 @@ public class AndroidResearchBuilder { private final ArrayList resolved_stacks = new ArrayList<>(); private List> resolved_preq; - record ResolvedFeature(AndroidFeatureType type, int level) { + record ResolvedFeature(AndroidFeatureType type, int level, Consumer callback) { } private final ArrayList resolved_features = new ArrayList<>(); @@ -152,7 +182,7 @@ public class AndroidResearchBuilder { var get = Registry.ANDROID_FEATURES().getValue(entry.id); if (get != null) { - resolved_features.add(new ResolvedFeature(get, entry.level)); + resolved_features.add(new ResolvedFeature(get, entry.level, entry.callback)); } else { throw new IllegalArgumentException("Can not find android feature " + entry); } @@ -246,8 +276,12 @@ public class AndroidResearchBuilder { if (get == null) { get = capability.addFeature(feature.type); get.setLevel(feature.level); - } else if (get.getLevel() < feature.level) { - get.setLevel(feature.level); + feature.callback.accept(get); + } else { + if (get.getLevel() < feature.level) + get.setLevel(feature.level); + + feature.callback.accept(get); } } } 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 new file mode 100644 index 000000000..492e3c52d --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsArmor.java @@ -0,0 +1,105 @@ +package ru.dbotthepony.mc.otm.android.feature; + +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.android.AndroidFeature; +import ru.dbotthepony.mc.otm.android.AndroidFeatureType; +import ru.dbotthepony.mc.otm.capability.IAndroidCapability; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; + +import java.math.BigDecimal; + +public class AndroidNanobotsArmor extends AndroidFeature { + public AndroidNanobotsArmor(AndroidFeatureType type, IAndroidCapability capability) { + super(type, 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 BigDecimal ENERGY_PER_BUILT = new BigDecimal(200); + protected static final BigDecimal ENERGY_PER_HITPOINT = new BigDecimal(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.multiply(new BigDecimal(Float.toString(absorbed))); + var extracted = capability.extractEnergyInner(required, false); + event.setAmount(event.getAmount() - absorbed * extracted.divide(required, MatteryCapability.ROUND_RULES).floatValue()); + 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 new file mode 100644 index 000000000..fba62657d --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/android/feature/AndroidNanobotsRegeneration.java @@ -0,0 +1,73 @@ +package ru.dbotthepony.mc.otm.android.feature; + +import net.minecraft.nbt.CompoundTag; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import ru.dbotthepony.mc.otm.android.AndroidFeature; +import ru.dbotthepony.mc.otm.android.AndroidFeatureType; +import ru.dbotthepony.mc.otm.capability.IAndroidCapability; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; + +import java.math.BigDecimal; + +public class AndroidNanobotsRegeneration extends AndroidFeature { + public AndroidNanobotsRegeneration(AndroidFeatureType type, IAndroidCapability capability) { + super(type, capability); + } + + protected int ticks_passed = 0; + protected int heal_ticks = 0; + + protected static final BigDecimal ENERGY_PER_HITPOINT = new BigDecimal(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.multiply(new BigDecimal(Float.toString(missing))), false); + + if (extract.compareTo(BigDecimal.ZERO) > 0) { + heal_ticks = Math.min(heal_ticks + 1, level); + ent.heal(missing * extract.divide(ENERGY_PER_HITPOINT, MatteryCapability.ROUND_RULES).floatValue()); + 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/capability/AndroidCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java index bc7af82e4..7594b3be8 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java @@ -17,6 +17,8 @@ import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fmllegacy.network.PacketDistributor; @@ -69,11 +71,11 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit } @Override - public AndroidFeature addFeature(@Nonnull AndroidFeatureType feature) { + public T addFeature(@Nonnull AndroidFeatureType feature) { var get = features.get(feature); if (get != null) - return get; + return (T) get; var factory = feature.factory(this); features.put(feature, factory); @@ -125,8 +127,8 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit } @Nullable - public AndroidFeature getFeature(AndroidFeatureType feature) { - return features.get(feature); + public T getFeature(AndroidFeatureType feature) { + return (T) features.get(feature); } public static final Set UNAFFECTED_EFFECTS = new HashSet<>(); @@ -181,6 +183,21 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit ent.getCapability(MatteryCapability.ANDROID).ifPresent(ent.level.isClientSide ? IAndroidCapability::tickClient : IAndroidCapability::tick); } + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void onHurtEvent(LivingHurtEvent event) { + if (event.isCanceled()) + return; + + var ent = event.getEntity(); + ent.getCapability(MatteryCapability.ANDROID).ifPresent((cap) -> cap.onHurt(event)); + } + + public void onHurt(LivingHurtEvent event) { + for (var feature : features.values()) { + feature.onHurt(event); + } + } + @Override @Nonnull public CompoundTag serializeNBT() { diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java index 31aac5740..414880c66 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java @@ -115,10 +115,10 @@ public class AndroidCapabilityPlayer extends AndroidCapability { return tag; } - public AndroidResearch getResearch(AndroidResearchType type) { + public T getResearch(AndroidResearchType type) { for (var instance : research_list) { if (instance.type == type) { - return instance; + return (T) instance; } } @@ -200,14 +200,14 @@ public class AndroidCapabilityPlayer extends AndroidCapability { var stats = ply.getFoodData(); - while (stats.getFoodLevel() < 17 && this.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, true).compareTo(ENERGY_FOR_HUNGER_POINT) == 0) { + while (stats.getFoodLevel() < 18 && this.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, true).compareTo(ENERGY_FOR_HUNGER_POINT) == 0) { this.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, false); stats.setFoodLevel(stats.getFoodLevel() + 1); } // "block" quick regeneration // also cause power to generate while in peaceful - while (stats.getFoodLevel() > 17 && this.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, true).compareTo(ENERGY_FOR_HUNGER_POINT) == 0) { + while (stats.getFoodLevel() > 18 && this.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, true).compareTo(ENERGY_FOR_HUNGER_POINT) == 0) { this.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, false); stats.setFoodLevel(stats.getFoodLevel() - 1); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java index 283f47e01..4c5526df4 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java @@ -4,6 +4,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.event.entity.living.LivingHurtEvent; import ru.dbotthepony.mc.otm.android.AndroidFeature; import ru.dbotthepony.mc.otm.android.AndroidFeatureType; import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage; @@ -18,14 +19,14 @@ public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializa void tickClient(); LivingEntity getEntity(); - AndroidFeature addFeature(@Nonnull AndroidFeatureType feature); + T addFeature(@Nonnull AndroidFeatureType feature); boolean removeFeature(@Nonnull AndroidFeatureType feature); boolean hasFeature(@Nullable AndroidFeatureType feature); boolean hasFeatureLevel(@Nullable AndroidFeatureType feature, int level); - AndroidFeature getFeature(AndroidFeatureType feature); + T getFeature(AndroidFeatureType feature); @Nonnull - default Optional getFeatureO(AndroidFeatureType feature) { + default Optional getFeatureO(AndroidFeatureType feature) { var get = getFeature(feature); return get != null ? Optional.of(get) : Optional.empty(); } @@ -33,6 +34,7 @@ public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializa default boolean isAndroid() { return true; } + default void onHurt(LivingHurtEvent event) {} @Nonnull ItemStack getBatteryItemStack(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java index a2280990b..d162e164e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java @@ -90,7 +90,7 @@ public class AndroidStationScreen extends MatteryScreen impl } public static final int FRAME_WIDTH = 210; - public static final int GRID_WIDTH = 6; + public static final int GRID_WIDTH = 5; public static final int GRID_HEIGHT = 5; public static final int FRAME_HEIGHT = 120; @@ -115,7 +115,7 @@ public class AndroidStationScreen extends MatteryScreen impl autoAttachToFrame(frame); - var grid = new GridPanel(this, frame, 0, 0, GRID_WIDTH * 18, 0, GRID_WIDTH, GRID_HEIGHT); + var grid = new GridPanel(this, frame, 0, 0, GRID_WIDTH * 22, 0, GRID_WIDTH, GRID_HEIGHT); minecraft.player.getCapability(MatteryCapability.ANDROID).ifPresent(_cap -> { if (_cap instanceof AndroidCapabilityPlayer cap) { diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index 06cd73931..7765c5ea6 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -49,21 +49,32 @@ "otm.matter_bottler.switch_mode": "Switch work mode", "android_feature.overdrive_that_matters.air_bags": "Air bags", - "android_feature.overdrive_that_matters.limb_overclocking_1": "Limb overclocking 1", - "android_feature.overdrive_that_matters.limb_overclocking_2": "Limb overclocking 2", - "android_feature.overdrive_that_matters.limb_overclocking_3": "Limb overclocking 3", - "android_feature.overdrive_that_matters.limb_overclocking_4": "Limb overclocking 4", "android_research.overdrive_that_matters.limb_overclocking": "Limb overclocking %s", - "android_research.overdrive_that_matters.limb_overclocking.description": "Boosts unit mobility by %s%% and attack speed by %s%%", + "android_research.overdrive_that_matters.limb_overclocking.description": "Boosts unit's mobility by %s%% and attack speed by %s%%", "android_research.status.requires": "Requires %s to be researched", "android_research.status.blocks": "Locks %s", "android_research.status.blocked_by": "Locked by %s", "android_research.overdrive_that_matters.air_bags": "Air bags", + "android_research.overdrive_that_matters.nanobots": "Nanobots", "android_research.overdrive_that_matters.air_bags.description": "Allows unit to swim in water", + "android_research.overdrive_that_matters.nanobots.description": "Various useful nanobots for doing various tasks", + + "android_research.overdrive_that_matters.nanobots_regeneration": "Regeneration %s", + "android_research.overdrive_that_matters.nanobots_regeneration.description": "Nanobots get ability to repair unit's internal systems on the move", + "android_research.overdrive_that_matters.nanobots_regeneration.description_improve": "Improves regeneration speed", + + "android_research.overdrive_that_matters.nanobots_armor": "Nanobots armor", + "android_research.overdrive_that_matters.nanobots_armor.description": "Allows nanobots to align themselves in cell shape, reducing incoming damage by a %% by absorbing impacts", + + "android_research.overdrive_that_matters.nanobots_armor_speed": "Nanobots armor build speed %s", + "android_research.overdrive_that_matters.nanobots_armor_speed.description": "Reduces time required for nanobots to form protection layer", + + "android_research.overdrive_that_matters.nanobots_armor_strength": "Nanobots armor build speed %s", + "android_research.overdrive_that_matters.nanobots_armor_strength.description": "Increases impact absorption strength of nanobots", "otm.suffix.merge": "%s %s",