diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index dbab2a27b..dbc0380d5 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -17,6 +17,7 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.RegistryBuilder; 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.block.*; @@ -372,14 +373,13 @@ public class Registry { ICON_UNKNOWN = new SkinElement(ICONS, x, y, 18, 18, 126, 126); } - public static final AndroidResearchType AIR_BAGS = new AndroidResearchType<>( - new ru.dbotthepony.mc.otm.android.AndroidResearch.Builder() + public static final AndroidResearchType AIR_BAGS = + new AndroidResearchBuilder() .setExperienceCost(18) .addFeatureResult(AndroidFeatures.AIR_BAGS) .withDescription() .withIcon(ICON_AIR_BAGS) - .build() - ); + .build(); public static final AndroidResearchType[] LIMB_OVERCLOCKING = new AndroidResearchType[4]; @@ -387,7 +387,7 @@ public class Registry { AIR_BAGS.setRegistryName(Names.AIR_BAGS); for (int i = 0; i < 4; i++) { - var builder = new ru.dbotthepony.mc.otm.android.AndroidResearch.Builder() + var builder = new AndroidResearchBuilder() .withDescription() .setExperienceCost(24 + i * 8) .withIconText(new TextComponent(String.valueOf(i + 1))) @@ -400,7 +400,7 @@ public class Registry { builder.addPrerequisite(Names.LIMB_OVERCLOCKING_LIST[i - 1]); } - LIMB_OVERCLOCKING[i] = new AndroidResearchType<>(builder.build()); + LIMB_OVERCLOCKING[i] = builder.build(); } LIMB_OVERCLOCKING[0].setRegistryName(Names.LIMB_OVERCLOCKING_1); diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearch.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearch.java index 32c791f6a..5cbd6786f 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearch.java +++ b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearch.java @@ -46,7 +46,18 @@ public abstract class AndroidResearch implements INBTSerializable { this.type = type; } - abstract public List> getPrerequisites(); + public List> getPrerequisites() { + return type.getPrerequisites(); + } + + public List> getBlocking() { + return type.getBlocking(); + } + + public List> getBlockedBy() { + return type.getBlockedBy(); + } + abstract public void onResearched(); abstract public void consumeCost(); abstract public boolean canAfford(); @@ -71,6 +82,12 @@ public abstract class AndroidResearch implements INBTSerializable { } } + for (var preq : getBlockedBy()) { + if (capability.getResearch(preq).isResearched()) { + return false; + } + } + return canAfford(); } @@ -119,295 +136,4 @@ public abstract class AndroidResearch implements INBTSerializable { researched = nbt.getByte("researched") > 0; } - public static class Builder { - record DeferredItemStack(ResourceLocation id, int amount) {} - record DeferredFeature(ResourceLocation id, int level) { - DeferredFeature(ResourceLocation id, int level) { - this.id = id; - this.level = level; - } - - DeferredFeature(ResourceLocation id) { - this(id, 0); - } - } - - public int experience = 0; - public Component text; - public boolean has_description = false; - public Component custom_description; - public Component custom_name; - public final ArrayList items = new ArrayList<>(); - public final ArrayList prerequisites = new ArrayList<>(); - public final ArrayList feature_results = new ArrayList<>(); - public SkinElement icon; - - public Builder addPrerequisite(ResourceLocation location) { - prerequisites.add(location); - return this; - } - - public Builder addPrerequisite(AndroidResearchType location) { - prerequisites.add(Objects.requireNonNull(location.getRegistryName())); - return this; - } - - public Builder addFeatureResult(ResourceLocation location) { - feature_results.add(new DeferredFeature(location)); - return this; - } - - public Builder addFeatureResult(AndroidFeatureType location) { - feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()))); - return this; - } - - public Builder addFeatureResult(ResourceLocation location, int level) { - feature_results.add(new DeferredFeature(location, level)); - return this; - } - - public Builder addFeatureResult(AndroidFeatureType location, int level) { - feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()), level)); - return this; - } - - public Builder addItem(ResourceLocation location) { - items.add(new DeferredItemStack(location, 1)); - return this; - } - - public Builder addItem(ResourceLocation location, int amount) { - items.add(new DeferredItemStack(location, amount)); - return this; - } - - public Builder setExperienceCost(int experience) { - this.experience = experience; - return this; - } - - public Builder withDescription() { - this.has_description = true; - return this; - } - - public Builder withDescription(Component text) { - this.has_description = true; - this.custom_description = text; - return this; - } - - public Builder withName(Component text) { - this.custom_name = text; - return this; - } - - public Builder withIcon(SkinElement icon) { - this.icon = icon; - return this; - } - - public Builder withIconText(Component text) { - this.text = text; - return this; - } - - private final ArrayList resolved_stacks = new ArrayList<>(); - private final ArrayList> resolved_preq = new ArrayList<>(); - - record ResolvedFeature(AndroidFeatureType type, int level) {} - - private final ArrayList resolved_features = new ArrayList<>(); - - private boolean resolved = false; - - private void resolve() { - if (!resolved) { - resolved = true; - - for (var item : items) { - var get_item = RegistryManager.ACTIVE.getRegistry(Item.class).getValue(item.id); - - if (get_item != null && get_item != Items.AIR) { - resolved_stacks.add(new ItemStack(get_item, item.amount)); - } - } - - for (var entry : prerequisites) { - var get = Registry.ANDROID_RESEARCH().getValue(entry); - - if (get != null) { - resolved_preq.add(get); - } else { - throw new IllegalArgumentException("Can not find android research " + entry); - } - } - - for (var entry : feature_results) { - var get = Registry.ANDROID_FEATURES().getValue(entry.id); - - if (get != null) { - resolved_features.add(new ResolvedFeature(get, entry.level)); - } else { - throw new IllegalArgumentException("Can not find android feature " + entry); - } - } - } - } - - public AndroidResearchType.AndroidResearchFactory build() { - return (type, capability) -> { - resolve(); - final var list_cp = List.copyOf(resolved_preq); - - return new AndroidResearch(type, capability) { - @Override - public Component getDisplayName() { - if (custom_name != null) - return custom_name; - - return super.getDisplayName(); - } - - @Nullable - @Override - public SkinElement getIcon() { - return icon; - } - - @Nullable - @Override - public Component getIconText() { - return text; - } - - @Override - public List getTooltip() { - var list = new ArrayList<>(super.getTooltip()); - - if (custom_description != null) { - list.add(custom_description); - } else if (has_description) { - list.add(new TranslatableComponent("android_research." + type.getRegistryName().getNamespace() + "." + type.getRegistryName().getPath() + ".description")); - } - - if (!researched) { - if (experience > 0) { - if (capability.ply.experienceLevel >= experience) { - list.add(new TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(ChatFormatting.DARK_GREEN)); - } else { - list.add(new TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(ChatFormatting.DARK_RED)); - } - } - - for (var stack : resolved_stacks) { - boolean hit = false; - - if (stack.getTag() == null) { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { - hit = true; - break; - } - } - } else { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { - hit = true; - break; - } - } - } - - if (hit) { - list.add(new TranslatableComponent("otm.android_station.research.item", stack.getDisplayName(), stack.getCount()).withStyle(ChatFormatting.DARK_GREEN)); - } else { - list.add(new TranslatableComponent("otm.android_station.research.item", stack.getDisplayName(), stack.getCount()).withStyle(ChatFormatting.DARK_RED)); - } - } - } - - return list; - } - - @Override - public List> getPrerequisites() { - return list_cp; - } - - @Override - public void onResearched() { - for (var feature : resolved_features) { - var get = capability.getFeature(feature.type); - - if (get == null) { - get = capability.addFeature(feature.type); - get.setLevel(feature.level); - } else if (get.getLevel() < feature.level) { - get.setLevel(feature.level); - } - } - } - - @Override - public boolean canAfford() { - if (capability.ply.experienceLevel < experience) - return false; - - for (var stack : resolved_stacks) { - boolean hit = false; - - if (stack.getTag() == null) { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { - hit = true; - break; - } - } - } else { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { - hit = true; - break; - } - } - } - - if (!hit) - return false; - } - - return true; - } - - @Override - public void consumeCost() { - if (experience > 0) - capability.ply.giveExperienceLevels(-experience); - - for (var stack : resolved_stacks) { - if (stack.getTag() == null) { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { - inv_stack.shrink(stack.getCount()); - break; - } - } - } else { - for (var inv_stack : capability.ply.getInventory().items) { - if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { - inv_stack.shrink(stack.getCount()); - break; - } - } - } - } - - capability.ply.getInventory().setChanged(); - } - }; - }; - } - } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java new file mode 100644 index 000000000..2465a92a0 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.java @@ -0,0 +1,328 @@ +package ru.dbotthepony.mc.otm.android; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.registries.RegistryManager; +import ru.dbotthepony.mc.otm.Registry; +import ru.dbotthepony.mc.otm.screen.SkinElement; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class AndroidResearchBuilder { + record DeferredItemStack(ResourceLocation id, int amount) { + } + + record DeferredFeature(ResourceLocation id, int level) { + DeferredFeature(ResourceLocation id, int level) { + this.id = id; + this.level = level; + } + + DeferredFeature(ResourceLocation id) { + this(id, 0); + } + } + + public int experience = 0; + public Component text; + public boolean has_description = false; + public Component custom_description; + public Component custom_name; + public final ArrayList items = new ArrayList<>(); + public final ArrayList prerequisites = new ArrayList<>(); + public final ArrayList feature_results = new ArrayList<>(); + public SkinElement icon; + + public AndroidResearchBuilder addPrerequisite(ResourceLocation location) { + prerequisites.add(location); + return this; + } + + public AndroidResearchBuilder addPrerequisite(AndroidResearchType location) { + prerequisites.add(Objects.requireNonNull(location.getRegistryName())); + return this; + } + + public AndroidResearchBuilder addFeatureResult(ResourceLocation location) { + feature_results.add(new DeferredFeature(location)); + return this; + } + + public AndroidResearchBuilder addFeatureResult(AndroidFeatureType location) { + feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()))); + return this; + } + + public AndroidResearchBuilder addFeatureResult(ResourceLocation location, int level) { + feature_results.add(new DeferredFeature(location, level)); + return this; + } + + public AndroidResearchBuilder addFeatureResult(AndroidFeatureType location, int level) { + feature_results.add(new DeferredFeature(Objects.requireNonNull(location.getRegistryName()), level)); + return this; + } + + public AndroidResearchBuilder addItem(ResourceLocation location) { + items.add(new DeferredItemStack(location, 1)); + return this; + } + + public AndroidResearchBuilder addItem(ResourceLocation location, int amount) { + items.add(new DeferredItemStack(location, amount)); + return this; + } + + public AndroidResearchBuilder setExperienceCost(int experience) { + this.experience = experience; + return this; + } + + public AndroidResearchBuilder withDescription() { + this.has_description = true; + return this; + } + + public AndroidResearchBuilder withDescription(Component text) { + this.has_description = true; + this.custom_description = text; + return this; + } + + public AndroidResearchBuilder withName(Component text) { + this.custom_name = text; + return this; + } + + public AndroidResearchBuilder withIcon(SkinElement icon) { + this.icon = icon; + return this; + } + + public AndroidResearchBuilder withIconText(Component text) { + this.text = text; + return this; + } + + private final ArrayList resolved_stacks = new ArrayList<>(); + private List> resolved_preq; + + record ResolvedFeature(AndroidFeatureType type, int level) { + } + + private final ArrayList resolved_features = new ArrayList<>(); + + private boolean resolved = false; + + private void resolve() { + if (!resolved) { + resolved = true; + + for (var item : items) { + var get_item = RegistryManager.ACTIVE.getRegistry(Item.class).getValue(item.id); + + if (get_item != null && get_item != Items.AIR) { + resolved_stacks.add(new ItemStack(get_item, item.amount)); + } + } + + var list = new ArrayList>(); + + for (var entry : prerequisites) { + var get = Registry.ANDROID_RESEARCH().getValue(entry); + + if (get != null) { + list.add(get); + } else { + throw new IllegalArgumentException("Can not find android research " + entry); + } + } + + resolved_preq = List.copyOf(list); + + for (var entry : feature_results) { + var get = Registry.ANDROID_FEATURES().getValue(entry.id); + + if (get != null) { + resolved_features.add(new ResolvedFeature(get, entry.level)); + } else { + throw new IllegalArgumentException("Can not find android feature " + entry); + } + } + } + } + + public AndroidResearchType build() { + return new AndroidResearchType<>((type, capability) -> { + resolve(); + + return new AndroidResearch(type, capability) { + @Nullable + @Override + public SkinElement getIcon() { + return icon; + } + + @Nullable + @Override + public Component getIconText() { + return text; + } + + @Override + public List getTooltip() { + var list = new ArrayList<>(super.getTooltip()); + + if (custom_description != null) { + list.add(custom_description); + } else if (has_description) { + list.add(new TranslatableComponent("android_research." + type.getRegistryName().getNamespace() + "." + type.getRegistryName().getPath() + ".description")); + } + + if (!researched) { + if (experience > 0) { + if (capability.ply.experienceLevel >= experience) { + list.add(new TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(ChatFormatting.DARK_GREEN)); + } else { + list.add(new TranslatableComponent("otm.android_station.research.xp_cost", experience).withStyle(ChatFormatting.DARK_RED)); + } + } + + for (var stack : resolved_stacks) { + boolean hit = false; + + if (stack.getTag() == null) { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { + hit = true; + break; + } + } + } else { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { + hit = true; + break; + } + } + } + + if (hit) { + list.add(new TranslatableComponent("otm.android_station.research.item", stack.getDisplayName(), stack.getCount()).withStyle(ChatFormatting.DARK_GREEN)); + } else { + list.add(new TranslatableComponent("otm.android_station.research.item", stack.getDisplayName(), stack.getCount()).withStyle(ChatFormatting.DARK_RED)); + } + } + + for (var research : getPrerequisites()) { + list.add(new TranslatableComponent("android_research.status.requires", research.getDisplayName()).withStyle(capability.getResearch(research).isResearched() ? ChatFormatting.DARK_GREEN : ChatFormatting.DARK_RED)); + } + } + + for (var research : getBlocking()) { + list.add(new TranslatableComponent("android_research.status.blocks", research.getDisplayName()).withStyle(ChatFormatting.DARK_RED)); + } + + for (var research : getBlockedBy()) { + list.add(new TranslatableComponent("android_research.status.blocked_by", research.getDisplayName()).withStyle(ChatFormatting.DARK_RED)); + } + + return list; + } + + @Override + public void onResearched() { + for (var feature : resolved_features) { + var get = capability.getFeature(feature.type); + + if (get == null) { + get = capability.addFeature(feature.type); + get.setLevel(feature.level); + } else if (get.getLevel() < feature.level) { + get.setLevel(feature.level); + } + } + } + + @Override + public boolean canAfford() { + if (capability.ply.experienceLevel < experience) + return false; + + for (var stack : resolved_stacks) { + boolean hit = false; + + if (stack.getTag() == null) { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { + hit = true; + break; + } + } + } else { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { + hit = true; + break; + } + } + } + + if (!hit) + return false; + } + + return true; + } + + @Override + public void consumeCost() { + if (experience > 0) + capability.ply.giveExperienceLevels(-experience); + + for (var stack : resolved_stacks) { + if (stack.getTag() == null) { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { + inv_stack.shrink(stack.getCount()); + break; + } + } + } else { + for (var inv_stack : capability.ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { + inv_stack.shrink(stack.getCount()); + break; + } + } + } + } + + capability.ply.getInventory().setChanged(); + } + }; + }) { + @Override + public List> getPrerequisites() { + resolve(); + return resolved_preq; + } + + @Override + public Component getDisplayName() { + if (custom_name != null) + return custom_name; + + return super.getDisplayName(); + } + }; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchType.java b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchType.java index 0df8d4aab..df38bf138 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchType.java +++ b/src/main/java/ru/dbotthepony/mc/otm/android/AndroidResearchType.java @@ -3,9 +3,48 @@ package ru.dbotthepony.mc.otm.android; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.registries.ForgeRegistryEntry; +import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer; +import java.util.ArrayList; +import java.util.List; + public class AndroidResearchType extends ForgeRegistryEntry> { + /** + * @return List of research required to be completed before this is unlocked + */ + public List> getPrerequisites() { + return List.of(); + } + + private List> blocking; + + /** + * @return List of research blocked once this research is unlocked + */ + public List> getBlocking() { + if (blocking == null) { + var list = new ArrayList>(); + + for (var type : Registry.ANDROID_RESEARCH()) { + if (type.getBlockedBy().contains(this)) { + list.add(type); + } + } + + blocking = List.copyOf(list); + } + + return blocking; + } + + /** + * @return List of research once unlocked blocks this research + */ + public List> getBlockedBy() { + return List.of(); + } + public interface AndroidResearchFactory { T factory(AndroidResearchType entry, AndroidCapabilityPlayer capability); } 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 dc0d97c8e..06cd73931 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 @@ -58,6 +58,10 @@ "android_research.overdrive_that_matters.limb_overclocking.description": "Boosts unit 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.air_bags.description": "Allows unit to swim in water",