Skip to content

Commit

Permalink
Implement mob effect modifier and migrate sticky to dynamic with that
Browse files Browse the repository at this point in the history
  • Loading branch information
KnightMiner committed Jan 8, 2023
1 parent ef65c78 commit 86c1af9
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "tconstruct:mob_effect",
"effect": "minecraft:slowness",
"level": {
"base": 0,
"multiplier": 1
},
"time": {
"base": 20,
"multiplier_flat": 10
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package slimeknights.tconstruct.library.modifiers.dynamic;

import com.google.gson.JsonObject;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.ProjectileHitModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.ProjectileLaunchModifierHook;
import slimeknights.tconstruct.library.modifiers.impl.IncrementalModifier;
import slimeknights.tconstruct.library.modifiers.util.ModifierHookMap;
import slimeknights.tconstruct.library.tools.context.EquipmentContext;
import slimeknights.tconstruct.library.tools.context.ToolAttackContext;
import slimeknights.tconstruct.library.tools.helper.ToolDamageUtil;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.library.tools.nbt.ModifierNBT;
import slimeknights.tconstruct.library.tools.nbt.NamespacedNBT;

import javax.annotation.Nullable;
import java.util.Objects;

/** Modifier that applies an effect on hit. Supports melee, armor, and ranged */
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class MobEffectModifier extends IncrementalModifier implements ProjectileHitModifierHook, ProjectileLaunchModifierHook {
private final MobEffect effect;
private final int levelBase;
private final int levelMultiplier;
private final int timeBase;
private final int timeMultiplierFlat;
private final int timeMultiplierRandom;

/** Applies the effect for the given level */
private void applyEffect(@Nullable LivingEntity target, float scaledLevel) {
if (target == null) {
return;
}
int level = Math.round(levelBase + scaledLevel * levelMultiplier - 1);
if (level < 0) {
return;
}
float duration = timeBase + scaledLevel * timeMultiplierFlat;
int randomBonus = (int)(timeMultiplierRandom * scaledLevel);
if (randomBonus > 0) {
duration += RANDOM.nextInt(randomBonus);
}
if (duration > 0) {
target.addEffect(new MobEffectInstance(effect, (int)duration, level));
}
}

@Override
public void onAttacked(IToolStackView tool, int level, EquipmentContext context, EquipmentSlot slotType, DamageSource source, float amount, boolean isDirectDamage) {
Entity attacker = source.getEntity();
if (isDirectDamage && attacker instanceof LivingEntity living) {
// 15% chance of working per level
float scaledLevel = getEffectiveLevel(tool, level);
if (RANDOM.nextFloat() < (scaledLevel * 0.25f)) {
applyEffect(living, scaledLevel);
ToolDamageUtil.damageAnimated(tool, 1, context.getEntity(), slotType);
}
}
}

@Override
public int afterEntityHit(IToolStackView tool, int level, ToolAttackContext context, float damageDealt) {
applyEffect(context.getLivingTarget(), getEffectiveLevel(tool, level));
return 0;
}

@Override
public void onProjectileLaunch(IToolStackView tool, ModifierEntry modifier, LivingEntity shooter, Projectile projectile, @Nullable AbstractArrow arrow, NamespacedNBT persistentData, boolean primary) {
persistentData.putFloat(getId(), modifier.getEffectiveLevel(tool));
}

@Override
public boolean onProjectileHitEntity(ModifierNBT modifiers, NamespacedNBT persistentData, ModifierEntry modifier, Projectile projectile, EntityHitResult hit, @Nullable LivingEntity attacker, @Nullable LivingEntity target) {
applyEffect(target, persistentData.getFloat(getId()));
return false;
}

@Override
protected void registerHooks(ModifierHookMap.Builder hookBuilder) {
hookBuilder.addHook(this, TinkerHooks.PROJECTILE_LAUNCH, TinkerHooks.PROJECTILE_HIT);
}

@Override
public IGenericLoader<? extends Modifier> getLoader() {
return LOADER;
}

/** Loader for this modifier */
public static final IGenericLoader<MobEffectModifier> LOADER = new IGenericLoader<>() {
@Override
public MobEffectModifier deserialize(JsonObject json) {
MobEffect effect = JsonHelper.getAsEntry(ForgeRegistries.MOB_EFFECTS, json, "effect");
int levelBase = 1;
int levelMultiplier = 0;
if (json.has("level")) {
JsonObject level = GsonHelper.getAsJsonObject(json, "level");
levelBase = GsonHelper.getAsInt(level, "base", 0);
levelMultiplier = GsonHelper.getAsInt(level, "multiplier", 0);
}
JsonObject time = GsonHelper.getAsJsonObject(json, "time");
int timeBase = GsonHelper.getAsInt(time, "base", 0);
int timeMultiplierFlat = GsonHelper.getAsInt(time, "multiplier_flat", 0);
int timeMultiplierRandom = GsonHelper.getAsInt(time, "multiplier_random", 0);
return new MobEffectModifier(effect, levelBase, levelMultiplier, timeBase, timeMultiplierFlat, timeMultiplierRandom);
}

@Override
public void serialize(MobEffectModifier object, JsonObject json) {
json.addProperty("effect", Objects.requireNonNull(object.effect.getRegistryName()).toString());
JsonObject level = new JsonObject();
level.addProperty("base", object.levelBase);
level.addProperty("multiplier", object.levelMultiplier);
json.add("level", level);
JsonObject time = new JsonObject();
time.addProperty("base", object.timeBase);
time.addProperty("multiplier_flat", object.timeMultiplierFlat);
time.addProperty("multiplier_flat", object.timeMultiplierRandom);
json.add("time", time);
}

@Override
public MobEffectModifier fromNetwork(FriendlyByteBuf buffer) {
MobEffect effect = buffer.readRegistryIdUnsafe(ForgeRegistries.MOB_EFFECTS);
int levelBase = buffer.readInt();
int levelMultiplier = buffer.readInt();
int timeBase = buffer.readInt();
int timeMultiplierFlat = buffer.readInt();
int timeMultiplierRandom = buffer.readInt();
return new MobEffectModifier(effect, levelBase, levelMultiplier, timeBase, timeMultiplierFlat, timeMultiplierRandom);
}

@Override
public void toNetwork(MobEffectModifier object, FriendlyByteBuf buffer) {
buffer.writeRegistryIdUnsafe(ForgeRegistries.MOB_EFFECTS, object.effect);
buffer.writeInt(object.levelBase);
buffer.writeInt(object.levelMultiplier);
buffer.writeInt(object.timeBase);
buffer.writeInt(object.timeMultiplierFlat);
buffer.writeInt(object.timeMultiplierRandom);
}
};

/** Builder for this modifier in datagen */
@RequiredArgsConstructor(staticName = "effect")
@Accessors(fluent = true)
public static class Builder {
private final MobEffect effect;
private int levelBase = 1;
private int levelMultiplier = 0;
@Setter
private int timeBase;
@Setter
private int timeMultiplierFlat;
@Setter
private int timeMultiplierRandom;

/**
* Sets the effect level
* @param base Base level granted for the modifier
* @param multiplier Bonus granted per level
* @return Builder
*/
public Builder level(int base, int multiplier) {
levelBase = base;
levelMultiplier = multiplier;
return this;
}

/** Builds the finished modifier */
public MobEffectModifier build() {
return new MobEffectModifier(effect, levelBase, levelMultiplier, timeBase, timeMultiplierFlat, timeMultiplierRandom);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import slimeknights.tconstruct.library.modifiers.dynamic.InventoryMenuModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.LootModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.MobDisguiseModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.MobEffectModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.StatBoostModifier;
import slimeknights.tconstruct.library.modifiers.impl.SingleLevelModifier;
import slimeknights.tconstruct.library.modifiers.impl.TankModifier;
Expand Down Expand Up @@ -188,7 +189,6 @@
import slimeknights.tconstruct.tools.modifiers.upgrades.armor.RicochetModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.armor.SoulSpeedModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.armor.SpringyModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.armor.StickyModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.armor.ThornsModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.general.ExperiencedModifier;
import slimeknights.tconstruct.tools.modifiers.upgrades.general.MagneticModifier;
Expand Down Expand Up @@ -325,7 +325,6 @@ public TinkerModifiers() {
// counterattack
public static final StaticModifier<ThornsModifier> thorns = MODIFIERS.register("thorns", ThornsModifier::new);
public static final StaticModifier<SpringyModifier> springy = MODIFIERS.register("springy", SpringyModifier::new);
public static final StaticModifier<StickyModifier> sticky = MODIFIERS.register("sticky", StickyModifier::new);
// helmet
public static final StaticModifier<RespirationModifier> respiration = MODIFIERS.register("respiration", RespirationModifier::new);
public static final StaticModifier<ItemFrameModifier> itemFrame = MODIFIERS.register("item_frame", ItemFrameModifier::new);
Expand Down Expand Up @@ -538,6 +537,7 @@ void registerSerializers(RegistryEvent.Register<RecipeSerializer<?>> event) {
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("conditional_mining_speed"), ConditionalMiningSpeedModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("loot"), LootModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("enchantment"), EnchantmentModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("mob_effect"), MobEffectModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("inventory_with_menu"), InventoryMenuModifier.LOADER);
// specialized
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("tool_belt"), ToolBeltModifier.LOADER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class ModifierIds {
// general
public static final ModifierId worldbound = id("worldbound");
public static final ModifierId shiny = id("shiny");
public static final ModifierId sticky = id("sticky");
// general abilities
public static final ModifierId reach = id("reach");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import slimeknights.tconstruct.library.modifiers.dynamic.InventoryMenuModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.LootModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.MobDisguiseModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.MobEffectModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.StatBoostModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.StatBoostModifier.ModifierDisplay;
import slimeknights.tconstruct.library.modifiers.util.ModifierLevelDisplay;
Expand Down Expand Up @@ -141,6 +142,7 @@ protected void addModifiers() {
addModifier(ModifierIds.looting, new LootModifier(1, ModifierLevelDisplay.DEFAULT));

/// attack
addModifier(ModifierIds.sticky, MobEffectModifier.Builder.effect(MobEffects.MOVEMENT_SLOWDOWN).level(0, 1).timeBase(20).timeMultiplierRandom(10).build());

// damage boost
// vanilla give +1, 1.5, 2, 2.5, 3, but that is low
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -743,13 +743,13 @@ private void addModifierRecipes(Consumer<FinishedRecipe> consumer) {
.setSlots(SlotType.UPGRADE, 1)
.saveSalvage(consumer, prefix(TinkerModifiers.thorns, upgradeSalvage))
.save(consumer, prefix(TinkerModifiers.thorns, upgradeFolder));
IncrementalModifierRecipeBuilder.modifier(TinkerModifiers.sticky)
IncrementalModifierRecipeBuilder.modifier(ModifierIds.sticky)
.setTools(ingredientFromTags(TinkerTags.Items.MELEE, TinkerTags.Items.ARMOR))
.setInput(Blocks.COBWEB, 1, 5)
.setSlots(SlotType.UPGRADE, 1)
.setMaxLevel(3)
.saveSalvage(consumer, prefix(TinkerModifiers.sticky, upgradeSalvage))
.save(consumer, prefix(TinkerModifiers.sticky, upgradeFolder));
.saveSalvage(consumer, prefix(ModifierIds.sticky, upgradeSalvage))
.save(consumer, prefix(ModifierIds.sticky, upgradeFolder));
ModifierRecipeBuilder.modifier(TinkerModifiers.springy)
.setTools(TinkerTags.Items.ARMOR)
.addInput(Items.PISTON)
Expand Down

This file was deleted.

0 comments on commit 86c1af9

Please sign in to comment.