Feature modifiers and levels, limb overclocking, research improvements

This commit is contained in:
DBotThePony 2021-08-23 11:46:13 +07:00
parent 38d34de609
commit 0365c09398
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 232 additions and 20 deletions

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.food.FoodProperties;
@ -16,6 +17,7 @@ import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryBuilder;
import ru.dbotthepony.mc.otm.android.AndroidFeature;
import ru.dbotthepony.mc.otm.android.AndroidResearchType;
import ru.dbotthepony.mc.otm.android.feature.AndroidLimbOverclocking;
import ru.dbotthepony.mc.otm.block.*;
import ru.dbotthepony.mc.otm.block.entity.*;
import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
@ -102,8 +104,15 @@ public class Registry {
public static final ResourceLocation NUTRIENT_PASTE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "nutrient_paste");
// android features
// 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");
public static final ResourceLocation LIMB_OVERCLOCKING_3 = new ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking_3");
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 class Blocks {
@ -277,14 +286,17 @@ public class Registry {
public static class AndroidFeatures {
public static final AndroidFeatureType<AndroidFeature> AIR_BAGS = new AndroidFeatureType<>(AndroidFeature::new);
public static final AndroidFeatureType<AndroidLimbOverclocking> LIMB_OVERCLOCKING = new AndroidFeatureType<>(AndroidLimbOverclocking::new);
static {
AIR_BAGS.setRegistryName(Names.AIR_BAGS);
LIMB_OVERCLOCKING.setRegistryName(Names.LIMB_OVERCLOCKING);
}
@SubscribeEvent
public static void register(final RegistryEvent.Register<AndroidFeatureType<?>> event) {
event.getRegistry().register(AIR_BAGS);
event.getRegistry().register(LIMB_OVERCLOCKING);
}
}
@ -358,13 +370,39 @@ public class Registry {
.build()
);
public static final AndroidResearchType<ru.dbotthepony.mc.otm.android.AndroidResearch>[] LIMB_OVERCLOCKING = new AndroidResearchType[4];
static {
AIR_BAGS.setRegistryName(Names.AIR_BAGS);
for (int i = 0; i < 4; i++) {
var builder = new ru.dbotthepony.mc.otm.android.AndroidResearch.Builder()
.withDescription()
.setExperienceCost(24 + i * 8)
.withIconText(new TextComponent(String.valueOf(i + 1)))
.withIcon(ICON_LIMB_OVERCLOCKING)
.addFeatureResult(Names.LIMB_OVERCLOCKING, i);
if (i > 0) {
builder.addPrerequisite(Names.LIMB_OVERCLOCKING_LIST[i - 1]);
}
LIMB_OVERCLOCKING[i] = new AndroidResearchType<>(builder.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);
}
@SubscribeEvent
public static void register(final RegistryEvent.Register<AndroidResearchType<?>> event) {
event.getRegistry().register(AIR_BAGS);
event.getRegistry().register(LIMB_OVERCLOCKING[0]);
event.getRegistry().register(LIMB_OVERCLOCKING[1]);
event.getRegistry().register(LIMB_OVERCLOCKING[2]);
event.getRegistry().register(LIMB_OVERCLOCKING[3]);
}
}

View File

@ -8,11 +8,24 @@ public class AndroidFeature implements INBTSerializable<CompoundTag> {
public final AndroidFeatureType<? extends AndroidFeature> 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))
@ -28,10 +41,6 @@ public class AndroidFeature implements INBTSerializable<CompoundTag> {
// when player forgets everything
}
public void attachFinish() {
// override
}
@Override
public int hashCode() {
return type.hashCode();
@ -45,8 +54,11 @@ public class AndroidFeature implements INBTSerializable<CompoundTag> {
}
public void serializeNBT(CompoundTag tag) {
public void applyModifiers() {}
public void removeModifiers() {}
public void serializeNBT(CompoundTag tag) {
tag.putInt("level", level);
}
@Override
@ -58,6 +70,6 @@ public class AndroidFeature implements INBTSerializable<CompoundTag> {
@Override
public void deserializeNBT(CompoundTag tag) {
level = tag.getInt("level");
}
}

View File

@ -76,6 +76,11 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
return true;
}
@Nullable
public Component getIconText() {
return null;
}
public boolean research() {
return research(false);
}
@ -102,12 +107,23 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
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 final ArrayList<DeferredItemStack> items = new ArrayList<>();
public final ArrayList<ResourceLocation> prerequisites = new ArrayList<>();
public final ArrayList<ResourceLocation> feature_results = new ArrayList<>();
public final ArrayList<DeferredFeature> feature_results = new ArrayList<>();
public SkinElement icon;
public Builder addPrerequisite(ResourceLocation location) {
@ -115,13 +131,28 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
return this;
}
public Builder addPrerequisite(AndroidResearchType<?> location) {
prerequisites.add(Objects.requireNonNull(location.getRegistryName()));
return this;
}
public Builder addFeatureResult(ResourceLocation location) {
feature_results.add(location);
feature_results.add(new DeferredFeature(location));
return this;
}
public Builder addFeatureResult(AndroidFeatureType<?> location) {
feature_results.add(Objects.requireNonNull(location.getRegistryName()));
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;
}
@ -150,9 +181,17 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
return this;
}
public Builder withIconText(Component text) {
this.text = text;
return this;
}
private final ArrayList<ItemStack> resolved_stacks = new ArrayList<>();
private final ArrayList<AndroidResearchType<?>> resolved_preq = new ArrayList<>();
private final ArrayList<AndroidFeatureType<?>> resolved_features = new ArrayList<>();
record ResolvedFeature(AndroidFeatureType<?> type, int level) {}
private final ArrayList<ResolvedFeature> resolved_features = new ArrayList<>();
private boolean resolved = false;
@ -179,10 +218,10 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
}
for (var entry : feature_results) {
var get = Registry.ANDROID_FEATURES().getValue(entry);
var get = Registry.ANDROID_FEATURES().getValue(entry.id);
if (get != null) {
resolved_features.add(get);
resolved_features.add(new ResolvedFeature(get, entry.level));
} else {
throw new IllegalArgumentException("Can not find android feature " + entry);
}
@ -201,6 +240,12 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
return icon;
}
@Nullable
@Override
public Component getIconText() {
return text;
}
@Override
public List<Component> getTooltip() {
var list = new ArrayList<>(super.getTooltip());
@ -256,12 +301,25 @@ public abstract class AndroidResearch implements INBTSerializable<CompoundTag> {
@Override
public void onResearched() {
for (var feature : resolved_features) {
capability.addFeature(feature);
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() {
for (var preq : resolved_preq) {
if (!capability.getResearch(preq).isResearched()) {
return false;
}
}
if (capability.ply.experienceLevel < experience)
return false;

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.mc.otm.android.feature;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
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.android.AndroidResearch;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import java.util.UUID;
public class AndroidLimbOverclocking extends AndroidFeature {
public final UUID MODIFIED_NAME = UUID.fromString("4a3fae46-e57b-4e20-857d-f5c2b2c8f2f2");
public AndroidLimbOverclocking(AndroidFeatureType<?> type, IAndroidCapability capability) {
super(type, capability);
}
@Override
public void applyModifiers() {
var speed = capability.getEntity().getAttribute(Attributes.MOVEMENT_SPEED);
OverdriveThatMatters.LOGGER.info("Get modifier {} {}", this, speed);
if (speed != null) {
speed.removePermanentModifier(MODIFIED_NAME);
speed.addPermanentModifier(new AttributeModifier(MODIFIED_NAME, type.getDisplayName().toString(), 0.08d * (level + 1), AttributeModifier.Operation.MULTIPLY_TOTAL));
OverdriveThatMatters.LOGGER.info("Add modifier {} {}", this, capability.getEntity());
}
}
@Override
public void removeModifiers() {
var speed = capability.getEntity().getAttribute(Attributes.MOVEMENT_SPEED);
if (speed != null) {
speed.removePermanentModifier(MODIFIED_NAME);
OverdriveThatMatters.LOGGER.info("Remove modifier {} {}", this, capability.getEntity());
}
}
}

View File

@ -20,6 +20,7 @@ import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fmllegacy.network.PacketDistributor;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.android.AndroidFeature;
import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
@ -46,6 +47,8 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
protected final Map<AndroidFeatureType<?>, AndroidFeature> features = new HashMap<>();
protected final ArrayList<Object> network_queue = new ArrayList<>();
protected final ArrayList<Runnable> delayed_tick_server = new ArrayList<>();
protected boolean network_first = false;
protected boolean addFeature(@Nonnull AndroidFeature feature) {
@ -54,6 +57,10 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
features.put(feature.type, feature);
if (!ent.level.isClientSide) {
delayed_tick_server.add(feature::applyModifiers);
}
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(true, feature));
}
@ -62,18 +69,24 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
}
@Override
public boolean addFeature(@Nonnull AndroidFeatureType<?> feature) {
if (features.containsKey(feature))
return false;
public AndroidFeature addFeature(@Nonnull AndroidFeatureType<?> feature) {
var get = features.get(feature);
if (get != null)
return get;
var factory = feature.factory(this);
features.put(feature, factory);
if (!ent.level.isClientSide) {
delayed_tick_server.add(factory::applyModifiers);
}
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(true, factory));
}
return true;
return factory;
}
@Override
@ -81,6 +94,10 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
var removed = features.remove(feature);
if (removed != null) {
if (!ent.level.isClientSide) {
delayed_tick_server.add(removed::removeModifiers);
}
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(false, removed));
}
@ -96,6 +113,17 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
return features.containsKey(feature);
}
@Override
public boolean hasFeatureLevel(@Nullable AndroidFeatureType<?> feature, int level) {
var get = features.get(feature);
if (get == null) {
return false;
}
return get.getLevel() >= level;
}
@Nullable
public AndroidFeature getFeature(AndroidFeatureType<?> feature) {
return features.get(feature);
@ -199,7 +227,10 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
feature.deserializeNBT(tag);
addFeature(feature);
feature.attachFinish();
if (ent.level == null || !ent.level.isClientSide) {
delayed_tick_server.add(feature::applyModifiers);
}
}
}
}
@ -265,6 +296,8 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
feature.tickClient();
}
}
delayed_tick_server.clear();
}
@Override
@ -277,6 +310,12 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
}
}
for (var runnable : delayed_tick_server) {
runnable.run();
}
delayed_tick_server.clear();
tickNetwork();
}

View File

@ -18,9 +18,10 @@ public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializa
void tickClient();
LivingEntity getEntity();
boolean addFeature(@Nonnull AndroidFeatureType<?> feature);
AndroidFeature 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);
@Nonnull

View File

@ -50,6 +50,12 @@ public class AndroidStationScreen extends MatteryScreen<AndroidStationMenu> {
} else {
RenderHelper.drawRect(stack, 0, 0, getWidth(), getHeight());
}
var text = node.getIconText();
if (text != null) {
font.drawShadow(stack, text, getWidth() - font.width(text), getHeight() - font.lineHeight, 0xFFFFFFFF);
}
}
});
}

View File

@ -44,6 +44,21 @@
"otm.android_station.research.missing_predecessors": "%s needs to be researched first",
"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_1": "Limb overclocking 1",
"android_research.overdrive_that_matters.limb_overclocking_2": "Limb overclocking 2",
"android_research.overdrive_that_matters.limb_overclocking_3": "Limb overclocking 3",
"android_research.overdrive_that_matters.limb_overclocking_4": "Limb overclocking 4",
"android_research.overdrive_that_matters.limb_overclocking_1.description": "Boosts unit mobility by 8%% and attack speed by 4%%",
"android_research.overdrive_that_matters.limb_overclocking_2.description": "Boosts unit mobility by 16%% and attack speed by 8%%",
"android_research.overdrive_that_matters.limb_overclocking_3.description": "Boosts unit mobility by 24%% and attack speed by 12%%",
"android_research.overdrive_that_matters.limb_overclocking_4.description": "Boosts unit mobility by 32%% and attack speed by 16%%",
"android_research.overdrive_that_matters.air_bags": "Air bags",
"android_research.overdrive_that_matters.air_bags.description": "Allows unit to swim in water",