Rewrite food effects and add an insect type

This commit is contained in:
Sollace 2021-08-17 19:06:04 +02:00
parent c45d6eb86a
commit 536502027d
32 changed files with 376 additions and 246 deletions

View file

@ -13,7 +13,6 @@ import com.google.common.base.Strings;
import com.minelittlepony.common.client.gui.sprite.TextureSprite; import com.minelittlepony.common.client.gui.sprite.TextureSprite;
import com.minelittlepony.common.client.gui.style.Style; import com.minelittlepony.common.client.gui.style.Style;
import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.item.toxin.FoodType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@ -50,19 +49,6 @@ public enum Race implements Affine {
return this == CHANGELING ? Affinity.BAD : Affinity.NEUTRAL; return this == CHANGELING ? Affinity.BAD : Affinity.NEUTRAL;
} }
public boolean canConsume(FoodType type) {
if (!isUsable()) {
return type != FoodType.FORAGE;
}
if (type.isMeat()) {
return this == BAT || this == CHANGELING || this == HUMAN;
}
if (type.isFish()) {
return this == PEGASUS || this == ALICORN;
}
return hasIronGut();
}
public boolean hasIronGut() { public boolean hasIronGut() {
return isUsable() && this != CHANGELING; return isUsable() && this != CHANGELING;
} }

View file

@ -24,8 +24,6 @@ import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.Trap; import com.minelittlepony.unicopia.entity.Trap;
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect; import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.toxin.FoodType;
import com.minelittlepony.unicopia.item.toxin.Toxicity;
import com.minelittlepony.unicopia.item.toxin.Toxin; import com.minelittlepony.unicopia.item.toxin.Toxin;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgOtherPlayerCapabilities; import com.minelittlepony.unicopia.network.MsgOtherPlayerCapabilities;
@ -420,7 +418,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
public void onEat(ItemStack stack) { public void onEat(ItemStack stack) {
if (getSpecies() == Race.CHANGELING) { if (getSpecies() == Race.CHANGELING) {
Toxin.POISON.afflict(getMaster(), FoodType.RAW_MEAT, Toxicity.SAFE, stack); Toxin.LOVE_SICKNESS.afflict(getMaster(), stack);
} }
} }

View file

@ -62,7 +62,7 @@ public interface UItems {
Item DAFFODIL_DAISY_SANDWICH = register("daffodil_daisy_sandwich", new Item(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.DAFODIL_DAISY_SANDWICH))); Item DAFFODIL_DAISY_SANDWICH = register("daffodil_daisy_sandwich", new Item(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.DAFODIL_DAISY_SANDWICH)));
Item HAY_BURGER = register("hay_burger", new Item(new Item.Settings().group(ItemGroup.FOOD).maxCount(1).food(UFoodComponents.HAY_BURGER))); Item HAY_BURGER = register("hay_burger", new Item(new Item.Settings().group(ItemGroup.FOOD).maxCount(1).food(UFoodComponents.HAY_BURGER)));
Item HAY_FRIES = register("hay_fries", new Item(new Item.Settings().group(ItemGroup.FOOD).maxCount(16).food(UFoodComponents.HAY_FRIES))); Item HAY_FRIES = register("hay_fries", new Item(new Item.Settings().group(ItemGroup.FOOD).maxCount(16).food(UFoodComponents.HAY_FRIES)));
Item WHEAT_WORMS = register("wheat_worms", new Item(new Item.Settings().group(ItemGroup.MISC).maxCount(16).food(UFoodComponents.WORMS))); Item WHEAT_WORMS = register("wheat_worms", new Item(new Item.Settings().group(ItemGroup.MISC).maxCount(16).food(UFoodComponents.INSECTS)));
Item MUG = register("mug", new Item(new Settings().group(ItemGroup.MATERIALS).maxCount(16))); Item MUG = register("mug", new Item(new Settings().group(ItemGroup.MATERIALS).maxCount(16)));
Item CIDER = register("cider", new DrinkableItem(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.CIDER).maxCount(1).recipeRemainder(MUG))); Item CIDER = register("cider", new DrinkableItem(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.CIDER).maxCount(1).recipeRemainder(MUG)));

View file

@ -0,0 +1,12 @@
package com.minelittlepony.unicopia.item.toxin;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
public interface Affliction {
void afflict(PlayerEntity player, ItemStack stack);
interface Predicate {
boolean test(PlayerEntity player, ItemStack stack);
}
}

View file

@ -1,29 +1,40 @@
package com.minelittlepony.unicopia.item.toxin; package com.minelittlepony.unicopia.item.toxin;
import java.util.List;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
public class Ailment { public class Ailment implements Affliction {
public static final Ailment INNERT = of(Toxicity.SAFE, Toxin.INNERT);
public static final Ailment INNERT = new Ailment(Toxicity.SAFE, Toxin.INNERT);
private final Toxicity toxicity; private final Toxicity toxicity;
private final Toxin toxin; private final Toxin effect;
public Ailment(Toxicity toxicity, Toxin toxin) { Ailment(Toxicity toxicity, Toxin effect) {
this.toxicity = toxicity; this.toxicity = toxicity;
this.toxin = toxin; this.effect = effect;
} }
public Toxicity getToxicity() { public Toxicity getToxicity() {
return toxicity; return toxicity;
} }
public void afflict(PlayerEntity player, FoodType type, ItemStack stack) { public void appendTooltip(List<Text> tooltip, TooltipContext context) {
this.toxin.afflict(player, type, toxicity, stack); tooltip.add(getToxicity().getTooltip());
if (context.isAdvanced()) {
effect.appendTooltip(tooltip);
}
} }
public static Ailment of(Toxicity toxicity) { @Override
return new Ailment(toxicity, Toxin.FOOD); public void afflict(PlayerEntity player, ItemStack stack) {
effect.afflict(player, stack);
}
public static Ailment of(Toxicity toxicity, Toxin effect) {
return new Ailment(toxicity, effect);
} }
} }

View file

@ -1,19 +0,0 @@
package com.minelittlepony.unicopia.item.toxin;
public enum FoodType {
RAW_MEAT, COOKED_MEAT,
RAW_FISH, COOKED_FISH,
FORAGE;
public boolean isRaw() {
return this == RAW_MEAT || this == RAW_FISH || this == FORAGE;
}
public boolean isMeat() {
return this == RAW_MEAT || this == COOKED_MEAT;
}
public boolean isFish() {
return this == RAW_FISH || this == COOKED_FISH;
}
}

View file

@ -1,7 +1,11 @@
package com.minelittlepony.unicopia.item.toxin; package com.minelittlepony.unicopia.item.toxin;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -18,22 +22,19 @@ import net.minecraft.world.World;
public class Toxic { public class Toxic {
private final UseAction action; private final UseAction action;
private final Ailment lowerBound;
private final Ailment upperBound;
private final FoodType type;
private final Optional<FoodComponent> component; private final Optional<FoodComponent> component;
private final Ailment defaultAilment;
private final Map<Race, Ailment> ailments;
private final Tag<Item> tag; private final Tag<Item> tag;
Toxic(UseAction action, FoodType type, Optional<FoodComponent> component, Tag<Item> tag, Ailment lowerBound, Ailment upperBound) { Toxic(UseAction action, Optional<FoodComponent> component, Tag<Item> tag, Ailment defaultAilment, Map<Race, Ailment> ailments) {
this.action = action; this.action = action;
this.type = type;
this.component = component; this.component = component;
this.tag = tag; this.tag = tag;
this.lowerBound = lowerBound; this.defaultAilment = defaultAilment;
this.upperBound = upperBound; this.ailments = ailments;
} }
public boolean matches(Item item) { public boolean matches(Item item) {
@ -49,16 +50,15 @@ public class Toxic {
} }
public Ailment getAilmentFor(PlayerEntity player) { public Ailment getAilmentFor(PlayerEntity player) {
Pony pony = Pony.of(player); if (player == null) {
if (pony != null && !pony.getSpecies().canConsume(type)) { return defaultAilment;
return upperBound;
} }
return lowerBound; return ailments.getOrDefault(Pony.of(player).getSpecies(), defaultAilment);
} }
public ItemStack finishUsing(ItemStack stack, World world, LivingEntity entity) { public ItemStack finishUsing(ItemStack stack, World world, LivingEntity entity) {
if (entity instanceof PlayerEntity) { if (entity instanceof PlayerEntity) {
getAilmentFor((PlayerEntity)entity).afflict((PlayerEntity)entity, type, stack); getAilmentFor((PlayerEntity)entity).afflict((PlayerEntity)entity, stack);
} }
return stack; return stack;
@ -70,4 +70,34 @@ public class Toxic {
} }
return null; return null;
} }
public static class Builder {
private final Ailment def;
private final Map<Race, Ailment> ailments = new EnumMap<>(Race.class);
private UseAction action = UseAction.EAT;
private Optional<FoodComponent> component = Optional.empty();
public Builder(Ailment def) {
this.def = def;
}
public Builder action(UseAction action) {
this.action = action;
return this;
}
public Builder food(FoodComponent food) {
component = Optional.ofNullable(food);
return this;
}
public Builder with(Race race, Ailment ailment) {
ailments.put(race, ailment);
return this;
}
public Toxic build(String name) {
return new Toxic(action, component, UTags.item(name), def, ailments);
}
}
} }

View file

@ -10,44 +10,18 @@ import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
public enum Toxicity { public enum Toxicity {
SAFE(0, 0), SAFE(Formatting.GRAY),
MILD(1, 160), MILD(Formatting.DARK_AQUA),
FAIR(1, 30), FAIR(Formatting.DARK_BLUE),
SEVERE(5, 160), SEVERE(Formatting.DARK_PURPLE),
LETHAL(10, 900); LETHAL(Formatting.RED);
private final int level;
private final int duration;
private static final Map<String, Toxicity> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Toxicity::name, Function.identity())); private static final Map<String, Toxicity> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Toxicity::name, Function.identity()));
Toxicity(int level, int duration) { private final Formatting color;
this.level = level;
this.duration = duration;
}
public int getLevel() { Toxicity(Formatting color) {
return level; this.color = color;
}
public int getDuration() {
return duration;
}
public boolean isMild() {
return this == MILD;
}
public boolean toxicWhenRaw() {
return isLethal() || this != SAFE;
}
public boolean toxicWhenCooked() {
return isLethal() || this == SEVERE;
}
public boolean isLethal() {
return this == LETHAL;
} }
public String getTranslationKey() { public String getTranslationKey() {
@ -55,9 +29,7 @@ public enum Toxicity {
} }
public Text getTooltip() { public Text getTooltip() {
return new TranslatableText(getTranslationKey()) return new TranslatableText(getTranslationKey()).formatted(color);
.styled(s -> s
.withColor(toxicWhenCooked() ? Formatting.RED : toxicWhenRaw() ? Formatting.DARK_PURPLE : Formatting.GRAY));
} }
public static Toxicity byName(String name) { public static Toxicity byName(String name) {

View file

@ -1,13 +1,9 @@
package com.minelittlepony.unicopia.item.toxin; package com.minelittlepony.unicopia.item.toxin;
import java.util.Optional; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.util.Registries; import com.minelittlepony.unicopia.util.Registries;
import net.minecraft.item.FoodComponent;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.UseAction;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import static com.minelittlepony.unicopia.item.toxin.Toxicity.*; import static com.minelittlepony.unicopia.item.toxin.Toxicity.*;
@ -16,46 +12,87 @@ import static com.minelittlepony.unicopia.item.toxin.Toxin.*;
public interface Toxics { public interface Toxics {
Registry<Toxic> REGISTRY = Registries.createSimple(new Identifier("unicopia:toxic")); Registry<Toxic> REGISTRY = Registries.createSimple(new Identifier("unicopia:toxic"));
Toxic EDIBLE = forage("edible", SAFE, FOOD); Toxic EDIBLE = register("forage_edible", new Toxic.Builder(Ailment.of(SAFE, INNERT))
Toxic RISKY = forage("risky", FAIR, FOOD); .food(UFoodComponents.RANDOM_FOLIAGE)
Toxic MODERATE = forage("moderate", MILD, FOOD); .with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING))
Toxic DANGEROUS = forage("dangerous", SEVERE, FOOD); );
Toxic NAUSEATING = forage("nauseating", SAFE, NAUSEA); Toxic RISKY = register("forage_risky", new Toxic.Builder(Ailment.of(FAIR, WEAK_NAUSEA.withChance(20)))
Toxic RADIOACTIVE = forage("radioactive", SAFE, RADIOACTIVITY); .food(UFoodComponents.RANDOM_FOLIAGE)
Toxic PRICKLY = forage("prickly", SAFE, DAMAGE); .with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING))
Toxic STRENGHTENING = forage("strengthening", SEVERE, STRENGTH); );
Toxic SEVERELY_NAUSEATING = forage("severely_nauseating", SEVERE, NAUSEA); Toxic MODERATE = register("forage_moderate", new Toxic.Builder(Ailment.of(MILD, POISON.and(WEAK_NAUSEA)))
Toxic BLINDING = forage("blinding", SEVERE, BLINDNESS); .food(UFoodComponents.RANDOM_FOLIAGE)
Toxic SEVERELY_PRICKLY = forage("severely_prickly", SEVERE, DAMAGE); .with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING))
);
Toxic DANGEROUS = register("forage_dangerous", new Toxic.Builder(Ailment.of(SEVERE, FOOD_POISONING))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(NAUSEA)))
);
Toxic NAUSEATING = register("forage_nauseating", new Toxic.Builder(Ailment.of(SAFE, NAUSEA.and(WEAKNESS.withChance(30))))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(NAUSEA)))
);
Toxic RADIOACTIVE = register("forage_radioactive", new Toxic.Builder(Ailment.of(SAFE, NAUSEA.and(RADIOACTIVITY.withChance(30))))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(NAUSEA)))
);
Toxic PRICKLY = register("forage_prickly", new Toxic.Builder(Ailment.of(SAFE, PRICKLING.withChance(30)))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(NAUSEA)))
);
Toxic STRENGHTENING = register("forage_strengthening", new Toxic.Builder(Ailment.of(SEVERE, STRENGTH.and(WEAK_NAUSEA)))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(WEAKNESS)))
);
Toxic SEVERELY_NAUSEATING = register("forage_severely_nauseating", new Toxic.Builder(Ailment.of(SEVERE, STRONG_NAUSEA.and(WEAKNESS)))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING.and(WEAKNESS)))
);
Toxic BLINDING = register("forage_blinding", new Toxic.Builder(Ailment.of(SEVERE, BLINDNESS.and(WEAK_NAUSEA)))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING))
);
Toxic SEVERELY_PRICKLY = register("forage_severely_prickly", new Toxic.Builder(Ailment.of(SEVERE, PRICKLING.and(NAUSEA)))
.food(UFoodComponents.RANDOM_FOLIAGE)
.with(Race.HUMAN, Ailment.of(LETHAL, FOOD_POISONING))
);
Toxic RAW_MEAT = register("raw_meat", new Toxic.Builder(Ailment.of(SEVERE, FOOD_POISONING.withChance(5).and(POISON.withChance(20))))
.with(Race.HUMAN, Ailment.INNERT)
.with(Race.BAT, Ailment.of(MILD, WEAK_NAUSEA))
);
Toxic ROTTEN_MEAT = register("rotten_meat", new Toxic.Builder(Ailment.of(SEVERE, FOOD_POISONING.and(POISON)))
.with(Race.HUMAN, Ailment.INNERT)
.with(Race.BAT, Ailment.of(MILD, STRONG_NAUSEA))
);
Toxic COOKED_MEAT = register("cooked_meat", new Toxic.Builder(Ailment.of(FAIR, FOOD_POISONING))
.with(Race.HUMAN, Ailment.INNERT)
.with(Race.BAT, Ailment.INNERT)
);
Toxic RAW_MEAT = meat(FoodType.RAW_MEAT, MILD); Toxic RAW_FISH = register("raw_fish", new Toxic.Builder(Ailment.of(FAIR, FOOD_POISONING.and(POISON)))
Toxic COOKED_MEAT = meat(FoodType.COOKED_MEAT, MILD); .with(Race.HUMAN, Ailment.INNERT)
.with(Race.PEGASUS, Ailment.of(MILD, POISON.and(WEAK_NAUSEA)))
.with(Race.ALICORN, Ailment.INNERT)
);
Toxic COOKED_FISH = register("cooked_fish", new Toxic.Builder(Ailment.of(MILD, FOOD_POISONING))
.with(Race.HUMAN, Ailment.INNERT)
.with(Race.PEGASUS, Ailment.INNERT)
.with(Race.ALICORN, Ailment.INNERT)
);
Toxic RAW_FISH = meat(FoodType.RAW_FISH, FAIR); Toxic RAW_INSECT = register("raw_insect", new Toxic.Builder(Ailment.of(LETHAL, FOOD_POISONING))
Toxic COOKED_FISH = meat(FoodType.COOKED_FISH, FAIR); .with(Race.BAT, Ailment.of(MILD, WEAK_NAUSEA))
);
Toxic COOKED_INSECT = register("cooked_insect", new Toxic.Builder(Ailment.of(LETHAL, FOOD_POISONING))
.food(UFoodComponents.INSECTS)
.with(Race.BAT, Ailment.INNERT)
);
static void bootstrap() {} static void bootstrap() {}
static Toxic forage(String name, Toxicity toxicity, Toxin toxin) { static Toxic register(String name, Toxic.Builder builder) {
if (toxin != FOOD) { name = "food_types/" + name;
toxin = FOOD.and(toxin); return Registry.register(REGISTRY, name, builder.build(name));
}
return register("forage_" + name, UseAction.EAT, FoodType.FORAGE,
Optional.of(UFoodComponents.RANDOM_FOLIAGE),
new Ailment(toxicity, toxin),
new Ailment(Toxicity.LETHAL, toxin));
}
static Toxic meat(FoodType type, Toxicity toxicity) {
return register(type.name().toLowerCase(), UseAction.EAT, type,
Optional.empty(),
Ailment.INNERT,
Ailment.of(toxicity));
}
static Toxic register(String name, UseAction action, FoodType type, Optional<FoodComponent> component,
Ailment lower,
Ailment upper) {
return Registry.register(REGISTRY, name, new Toxic(action, type, component, UTags.item(name), lower, upper));
} }
} }

View file

@ -1,72 +1,137 @@
package com.minelittlepony.unicopia.item.toxin; package com.minelittlepony.unicopia.item.toxin;
import java.util.List;
import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.FoodComponent; import net.minecraft.item.FoodComponent;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.ChatUtil;
import net.minecraft.world.Difficulty; import net.minecraft.world.Difficulty;
@FunctionalInterface public interface Toxin extends Affliction {
public interface Toxin { Predicate IF_NOT_PEACEFUL = Predicate.of(Text.of("when not in peaceful "), (player, stack) -> player.world.getDifficulty() != Difficulty.PEACEFUL);
Predicate ONE_EVERY_30_TICKS = (player, type, toxicity, stack) -> player.world.random.nextInt(30) == 0;
Toxin INNERT = (player, type, toxicity, stack) -> {}; Toxin INNERT = of(Text.of("No Effect"), (player, stack) -> {});
Toxin DAMAGE = ONE_EVERY_30_TICKS.then(of(StatusEffects.INSTANT_DAMAGE, 1, 1));
Toxin RADIOACTIVITY = ONE_EVERY_30_TICKS.then(of(StatusEffects.GLOWING, 10, 1)); Toxin PRICKLING = of(StatusEffects.INSTANT_DAMAGE, 1, 0);
Toxin NAUSEA = of(StatusEffects.NAUSEA, 30, 1); Toxin RADIOACTIVITY = of(StatusEffects.GLOWING, 15, 0);
Toxin WEAK_NAUSEA = of(StatusEffects.NAUSEA, 3, 1);
Toxin STRENGTH = of(StatusEffects.STRENGTH, 30, 1); Toxin WEAKNESS = of(StatusEffects.WEAKNESS, 200, 1);
Toxin BLINDNESS = of(StatusEffects.BLINDNESS, 30, 1);
Toxin POISON = (player, type, toxicity, stack) -> { Toxin WEAK_NAUSEA = of(StatusEffects.NAUSEA, 17, 0);
Toxin NAUSEA = of(StatusEffects.NAUSEA, 20, 1);
Toxin STRONG_NAUSEA = of(StatusEffects.NAUSEA, 30, 1);
Toxin STRENGTH = of(StatusEffects.STRENGTH, 30, 0);
Toxin BLINDNESS = of(StatusEffects.BLINDNESS, 30, 0);
Toxin POISON = of(StatusEffects.POISON, 45, 2);
Toxin FOOD_POISONING = of(UEffects.FOOD_POISONING, 300, 2);
Toxin WEAK_FOOD_POISONING = of(UEffects.FOOD_POISONING, 150, 1);
Toxin LOVE_SICKNESS = of(Text.of("Love Sickness "), (player, stack) -> {
FoodComponent food = stack.getItem().getFoodComponent(); FoodComponent food = stack.getItem().getFoodComponent();
player.getHungerManager().add(-food.getHunger()/2, -food.getSaturationModifier()/2); player.getHungerManager().add(-food.getHunger()/2, -food.getSaturationModifier()/2);
afflict(player, StatusEffects.NAUSEA, 1700, 10); }).and(STRONG_NAUSEA).and(IF_NOT_PEACEFUL.then(WEAK_FOOD_POISONING.withChance(20))).and(WEAKNESS);
if (player.world.getDifficulty() != Difficulty.PEACEFUL && player.world.random.nextInt(20) == 0) { default void appendTooltip(List<Text> tooltip) {
afflict(player, UEffects.FOOD_POISONING, 150, 2); tooltip.add(getName());
} }
afflict(player, StatusEffects.WEAKNESS, 2000, 20); default Toxin withChance(int max) {
}; return Predicate.of(Text.of("1 in " + max + " chance of "), (player, stack) -> player.world.random.nextInt(max) == 0).then(this);
Toxin FOOD = (player, type, toxicity, stack) -> {
if (toxicity.toxicWhenRaw() && type.isRaw()) {
player.addStatusEffect(new StatusEffectInstance(toxicity.isMild() ? StatusEffects.NAUSEA : StatusEffects.POISON, toxicity.getDuration(), toxicity.getLevel()));
} }
if (toxicity.isLethal()) { Text getName();
player.addStatusEffect(new StatusEffectInstance(UEffects.FOOD_POISONING, 300, 7, false, false));
} else if (toxicity.toxicWhenCooked()) {
WEAK_NAUSEA.afflict(player, type, toxicity, stack);
}
};
void afflict(PlayerEntity player, FoodType type, Toxicity toxicity, ItemStack stack);
default Toxin and(Toxin other) { default Toxin and(Toxin other) {
Toxin self = this; Toxin self = this;
return (player, type, toxicity, stack) -> { return new Toxin() {
self.afflict(player, type, toxicity, stack); @Override
other.afflict(player, type, toxicity, stack); public void afflict(PlayerEntity player, ItemStack stack) {
self.afflict(player, stack);
other.afflict(player, stack);
}
@Override
public void appendTooltip(List<Text> tooltip) {
self.appendTooltip(tooltip);
other.appendTooltip(tooltip);
}
@Override
public Text getName() {
return self.getName().shallowCopy().append(" + ").append(other.getName());
}
}; };
} }
static Toxin of(StatusEffect effect, int duration, int amplifier) { static Toxin of(Text name, Affliction affliction) {
return (player, type, toxicity, stack) -> afflict(player, effect, duration, amplifier); return new Toxin() {
@Override
public void afflict(PlayerEntity player, ItemStack stack) {
affliction.afflict(player, stack);
} }
static void afflict(PlayerEntity player, StatusEffect effect, int duration, int amplifier) { @Override
player.addStatusEffect(new StatusEffectInstance(effect, duration, amplifier, false, false)); public Text getName() {
return name;
}
};
}
static Toxin of(StatusEffect effect, int seconds, int amplifier) {
int ticks = seconds * 20;
MutableText text = effect.getName().shallowCopy();
if (amplifier > 0) {
text = new TranslatableText("potion.withAmplifier", text, new TranslatableText("potion.potency." + amplifier));
}
text = new TranslatableText("potion.withDuration", text, ChatUtil.ticksToString(ticks));
return of(text, (player, stack) -> {
player.addStatusEffect(new StatusEffectInstance(effect, ticks, amplifier, false, false, false));
});
} }
interface Predicate { interface Predicate {
boolean test(PlayerEntity player, FoodType type, Toxicity toxicity, ItemStack stack); static Predicate of(Text name, Affliction.Predicate predicate) {
return new Predicate() {
@Override
public boolean test(PlayerEntity player, ItemStack stack) {
return predicate.test(player, stack);
}
@Override
public Text getName() {
return name;
}
};
}
boolean test(PlayerEntity player, ItemStack stack);
Text getName();
default Toxin then(Toxin toxin) { default Toxin then(Toxin toxin) {
return (player, type, toxicity, stack) -> { return new Toxin() {
if (test(player, type, toxicity, stack)) { @Override
toxin.afflict(player, type, toxicity, stack); public void afflict(PlayerEntity player, ItemStack stack) {
if (test(player, stack)) {
toxin.afflict(player, stack);
}
}
@Override
public Text getName() {
return Predicate.this.getName().shallowCopy().append(toxin.getName());
} }
}; };
} }

View file

@ -11,17 +11,20 @@ import net.minecraft.util.Identifier;
public interface UEffects { public interface UEffects {
StatusEffect FOOD_POISONING = new CustomStatusEffect(new Identifier("unicopia", "food_poisoning"), StatusEffectType.BENEFICIAL, 3484199) StatusEffect FOOD_POISONING = new CustomStatusEffect.Builder(new Identifier("unicopia", "food_poisoning"), StatusEffectType.HARMFUL, 3484199).direct((p, e, i) -> {
.setSilent()
.direct((p, e, i) -> {
StatusEffectInstance nausea = e.getStatusEffect(StatusEffects.NAUSEA); StatusEffectInstance nausea = e.getStatusEffect(StatusEffects.NAUSEA);
if (nausea == null) { if (nausea == null) {
StatusEffectInstance foodEffect = e.getStatusEffect(p); StatusEffectInstance foodEffect = e.getStatusEffect(p);
nausea = new StatusEffectInstance(StatusEffects.NAUSEA, foodEffect.getDuration(), foodEffect.getAmplifier(), foodEffect.isAmbient(), foodEffect.shouldShowParticles()); nausea = new StatusEffectInstance(StatusEffects.NAUSEA, foodEffect.getDuration(),
foodEffect.getAmplifier(),
true,
foodEffect.shouldShowParticles(),
false
);
e.addStatusEffect(nausea); e.addStatusEffect(nausea);
} }
e.damage(MagicalDamageSource.FOOD_POISONING, i); e.damage(MagicalDamageSource.FOOD_POISONING, i);
}); }).build();
} }

View file

@ -15,10 +15,12 @@ public interface UFoodComponents {
FoodComponent HAY_FRIES = builder(1, 5).build(); FoodComponent HAY_FRIES = builder(1, 5).build();
FoodComponent SALAD = builder(4, 2).build(); FoodComponent SALAD = builder(4, 2).build();
FoodComponent CIDER = builder(4, 2).alwaysEdible().build(); FoodComponent CIDER = builder(4, 2).alwaysEdible().build();
FoodComponent RANDOM_FOLIAGE = builder(2, 1).build();
FoodComponent JUICE = builder(2, 2).alwaysEdible().build(); FoodComponent JUICE = builder(2, 2).alwaysEdible().build();
FoodComponent BURNED_JUICE = builder(3, 1).build(); FoodComponent BURNED_JUICE = builder(3, 1).build();
FoodComponent WORMS = builder(1, 0).alwaysEdible().build();
FoodComponent RANDOM_FOLIAGE = builder(2, 1).build();
FoodComponent INSECTS = builder(1, 0).alwaysEdible().build();
FoodComponent CEREAL = builder(9, 0.8F).build(); FoodComponent CEREAL = builder(9, 0.8F).build();
FoodComponent SUGAR = builder(20, -2).build(); FoodComponent SUGAR = builder(20, -2).build();

View file

@ -20,6 +20,6 @@ import net.minecraft.world.World;
abstract class MixinItem implements ToxicHolder { abstract class MixinItem implements ToxicHolder {
@Inject(method = "appendTooltip", at = @At("RETURN")) @Inject(method = "appendTooltip", at = @At("RETURN"))
private void onAppendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context, CallbackInfo into) { private void onAppendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context, CallbackInfo into) {
getToxic().ifPresent(t -> tooltip.add(t.getAilmentFor(MinecraftClient.getInstance().player).getToxicity().getTooltip())); getToxic().ifPresent(t -> t.getAilmentFor(MinecraftClient.getInstance().player).appendTooltip(tooltip, context));
} }
} }

View file

@ -11,47 +11,17 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
public class CustomStatusEffect extends StatusEffect { public class CustomStatusEffect extends StatusEffect {
private final boolean instant;
private final int rate;
private final Direct direct;
private final Indirect indirect;
private int tickDelay = 40; public CustomStatusEffect(StatusEffectType type, int color, int rate, boolean instant, Direct direct, Indirect indirect) {
@NotNull
private DirectEffect direct = DirectEffect.NONE;
@NotNull
private IndirectEffect indirect = IndirectEffect.NONE;
public CustomStatusEffect(Identifier id, StatusEffectType type, int color) {
super(type, color); super(type, color);
this.direct = direct;
Registry.register(Registry.STATUS_EFFECT, id, this); this.rate = rate;
} this.indirect = indirect;
this.instant = instant;
public CustomStatusEffect setSilent() {
return this;
}
public CustomStatusEffect direct(@NotNull DirectEffect applicator) {
this.direct = applicator;
return this;
}
public CustomStatusEffect indirect(@NotNull IndirectEffect applicator) {
this.indirect = applicator;
return this;
}
public CustomStatusEffect setTickDelay(int delay) {
tickDelay = delay;
return this;
}
public CustomStatusEffect setEffectiveness(double effectiveness) {
return this;
} }
@Override @Override
@ -66,32 +36,74 @@ public class CustomStatusEffect extends StatusEffect {
@Override @Override
public boolean isInstant() { public boolean isInstant() {
return tickDelay > 0; return instant;
} }
@Override @Override
public boolean canApplyUpdateEffect(int duration, int amplifier) { public boolean canApplyUpdateEffect(int duration, int amplifier) {
if (!isInstant()) { if (isInstant()) {
int i = tickDelay >> amplifier;
if (i > 0) {
return duration % i == 0;
}
}
return duration > 0; return duration > 0;
} }
int i = rate >> amplifier;
return i <= 0 || duration % i == 0;
}
public static class Builder {
private final Identifier id;
private final StatusEffectType type;
private final int color;
private boolean instant;
private int rate = 40;
@NotNull
private Direct direct = Direct.NONE;
@NotNull
private Indirect indirect = Indirect.NONE;
public Builder(Identifier id, StatusEffectType type, int color) {
this.id = id;
this.type = type;
this.color = color;
}
public Builder instant() {
instant = true;
return this;
}
public Builder rate(int rate) {
this.rate = rate;
return this;
}
public Builder direct(@NotNull Direct applicator) {
this.direct = applicator;
return this;
}
public Builder indirect(@NotNull Indirect applicator) {
this.indirect = applicator;
return this;
}
public StatusEffect build() {
return Registry.register(Registry.STATUS_EFFECT, id, new CustomStatusEffect(type, color, rate, instant, direct, indirect));
}
}
@FunctionalInterface @FunctionalInterface
public interface DirectEffect { public interface Direct {
DirectEffect NONE = (p, e, i) -> {}; Direct NONE = (p, e, i) -> {};
void perform(StatusEffect effect, LivingEntity target, int amplifier); void perform(StatusEffect effect, LivingEntity target, int amplifier);
} }
@FunctionalInterface @FunctionalInterface
public interface IndirectEffect { public interface Indirect {
IndirectEffect NONE = (p, s, a, t, A, d) -> {}; Indirect NONE = (p, s, a, t, A, d) -> {};
void perform(StatusEffect effect, @Nullable Entity source, @Nullable Entity attacker, LivingEntity target, int amplifier, double distance); void perform(StatusEffect effect, @Nullable Entity source, @Nullable Entity attacker, LivingEntity target, int amplifier, double distance);
} }

View file

@ -74,7 +74,7 @@
"unicopia.effect.tribe.stage.determination": "As your bones realign you are filled by determination.", "unicopia.effect.tribe.stage.determination": "As your bones realign you are filled by determination.",
"unicopia.effect.tribe.stage.resurection": "Knowing you will return to this world as a %s", "unicopia.effect.tribe.stage.resurection": "Knowing you will return to this world as a %s",
"effect.food_poisoning": "Food Poisoning", "effect.unicopia.food_poisoning": "Food Poisoning",
"player.reachDistance": "Reach Distance", "player.reachDistance": "Reach Distance",
"player.miningSpeed": "Mining Speed", "player.miningSpeed": "Mining Speed",
@ -112,6 +112,8 @@
"item.minecraft.lingering_potion.effect.unicopia.tribe_swap_bat": "Lingering Potion of Bat Pony Metamorphosis", "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_bat": "Lingering Potion of Bat Pony Metamorphosis",
"item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_bat": "Arrow of Bat Pony Metamorphosis", "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_bat": "Arrow of Bat Pony Metamorphosis",
"potion.potency.6": "VII",
"spell.unicopia.frost": "Frost", "spell.unicopia.frost": "Frost",
"spell.unicopia.frost.lore": "Ice I", "spell.unicopia.frost.lore": "Ice I",

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:fermented_spider_eye"
]
}

View file

@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"minecraft:spider_eye",
"unicopia:wheat_worms"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:rotten_flesh"
]
}