diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index 934eb559..4eb23663 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -6,6 +6,8 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import javax.annotation.Nullable; + import com.google.common.base.Strings; import com.minelittlepony.common.client.gui.sprite.TextureSprite; import com.minelittlepony.common.client.gui.style.Style; @@ -80,7 +82,7 @@ public enum Race implements Affine { return String.format("unicopia.race.%s", name().toLowerCase()); } - public boolean isPermitted(PlayerEntity sender) { + public boolean isPermitted(@Nullable PlayerEntity sender) { if (isOp() && (sender == null || !sender.abilities.creativeMode)) { return false; } diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 580c2c08..902addf4 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -6,6 +6,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.minelittlepony.unicopia.command.Commands; +import com.minelittlepony.unicopia.entity.effect.UPotions; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.network.Channel; @@ -35,5 +36,6 @@ public class Unicopia implements ModInitializer { ServerTickEvents.END_WORLD_TICK.register(AwaitTickQueue::tick); UItems.bootstrap(); + UPotions.bootstrap(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java new file mode 100644 index 00000000..f90d7955 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/RaceChangeStatusEffect.java @@ -0,0 +1,146 @@ +package com.minelittlepony.unicopia.entity.effect; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.entity.Equine; +import com.minelittlepony.unicopia.entity.PonyContainer; +import com.minelittlepony.unicopia.entity.player.MagicReserves; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.util.MagicalDamageSource; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffectType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class RaceChangeStatusEffect extends StatusEffect { + public static final int STAGE_DURATION = 50; + public static final int MAX_DURATION = Stage.VALUES.length * STAGE_DURATION + 1; + + public static final RaceChangeStatusEffect CHANGE_RACE_EARTH = new RaceChangeStatusEffect(0x886F0F, Race.EARTH); + public static final RaceChangeStatusEffect CHANGE_RACE_UNICORN = new RaceChangeStatusEffect(0x88FFFF, Race.UNICORN); + public static final RaceChangeStatusEffect CHANGE_RACE_PEGASUS = new RaceChangeStatusEffect(0x00FFFF, Race.PEGASUS); + public static final RaceChangeStatusEffect CHANGE_RACE_BAT = new RaceChangeStatusEffect(0x0FFF00, Race.BAT); + public static final RaceChangeStatusEffect CHANGE_RACE_CHANGELING = new RaceChangeStatusEffect(0xFFFF00, Race.CHANGELING); + + private final Race species; + + protected RaceChangeStatusEffect(int color, Race species) { + super(StatusEffectType.NEUTRAL, color); + this.species = species; + + Registry.register(Registry.STATUS_EFFECT, new Identifier("unicopia", "change_race_" + species.name().toLowerCase()), this); + } + + public Race getSpecies() { + return species; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + StatusEffectInstance state = entity.getStatusEffect(this); + + if (state == null) { + return; + } + + Equine eq = Equine.of(entity); + + if (eq == null) { + return; + } + + int ticks = Math.max(0, MAX_DURATION - state.getDuration()); + + Stage stage = Stage.forDuration(ticks / STAGE_DURATION); + + if (stage == Stage.INITIAL) { + return; + } + + int progression = ticks % (stage.ordinal() * STAGE_DURATION); + + if (eq.getSpecies() == species || !species.isPermitted(entity instanceof PlayerEntity ? (PlayerEntity)entity : null)) { + if (progression == 0 && entity instanceof PlayerEntity && stage == Stage.CRAWLING) { + ((PlayerEntity)entity).sendMessage(Stage.INITIAL.getMessage(species), true); + } + return; + } + + if (progression == 0) { + if (stage != Stage.DEATH && entity instanceof PlayerEntity) { + ((PlayerEntity)entity).sendMessage(stage.getMessage(species), true); + } + + float hitAmount = entity.getHealth() / 2; + + if (hitAmount > 1) { + entity.damage(DamageSource.MAGIC, hitAmount); + } + } + + if (entity instanceof PlayerEntity) { + Pony pony = (Pony)eq; + MagicReserves magic = pony.getMagicalReserves(); + magic.addExertion(50); + magic.addEnergy(3); + + if (state.shouldShowParticles()) { + pony.spawnParticles(ParticleTypes.TOTEM_OF_UNDYING, 5); + } + } + + if (stage == Stage.DEATH) { + PonyContainer.of(entity).map(PonyContainer::get).ifPresent(e -> { + e.setSpecies(species); + if (e instanceof Pony) { + ((Pony)e).setDirty(); + } + }); + entity.damage(MagicalDamageSource.TRIBE_SWAP, Float.MAX_VALUE); + } + } + + @Override + public void applyInstantEffect(@Nullable Entity source, @Nullable Entity attacker, LivingEntity target, int amplifier, double proximity) { + this.applyUpdateEffect(target, amplifier); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return duration > 0; + } + + enum Stage { + INITIAL, + CRAWLING, + DETERMINATION, + RESURECTION, + DEATH; + + static Stage[] VALUES = values(); + + public static Stage forDuration(int duration) { + return VALUES[duration % VALUES.length]; + } + + public String getTranslationKey() { + return String.format("unicopia.effect.tribe.stage.%s", name().toLowerCase()); + } + + public Text getMessage(Race species) { + return new TranslatableText(getTranslationKey(), new TranslatableText(species.getTranslationKey())); + } + } + + static void bootstrap() { } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java new file mode 100644 index 00000000..c18bc2b9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java @@ -0,0 +1,26 @@ +package com.minelittlepony.unicopia.entity.effect; + +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.potion.Potion; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public interface UPotions { + Potion TRIBE_SWAP_EARTH_PONY = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_EARTH); + Potion TRIBE_SWAP_UNICORN = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_UNICORN); + Potion TRIBE_SWAP_PEGASUS = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_PEGASUS); + Potion TRIBE_SWAP_BAT = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_BAT); + Potion TRIBE_SWAP_CHANGELING = registerRacePotion(RaceChangeStatusEffect.CHANGE_RACE_CHANGELING); + + static Potion registerRacePotion(RaceChangeStatusEffect effect) { + String name = "tribe_swap_" + effect.getSpecies().name().toLowerCase(); + return register(name, new Potion("unicopia." + name, + new StatusEffectInstance(effect, RaceChangeStatusEffect.MAX_DURATION))); + } + + static Potion register(String name, Potion potion) { + return Registry.register(Registry.POTION, new Identifier("unicopia", name), potion); + } + + static void bootstrap() {} +} diff --git a/src/main/java/com/minelittlepony/unicopia/util/MagicalDamageSource.java b/src/main/java/com/minelittlepony/unicopia/util/MagicalDamageSource.java index cf09d5cf..84eed7bb 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/MagicalDamageSource.java +++ b/src/main/java/com/minelittlepony/unicopia/util/MagicalDamageSource.java @@ -17,6 +17,7 @@ public class MagicalDamageSource extends EntityDamageSource { public static final DamageSource EXHAUSTION = new MagicalDamageSource("magical_exhaustion", true, true); public static final DamageSource FOOD_POISONING = mundane("food_poisoning"); + public static final DamageSource TRIBE_SWAP = mundane("tribe_swap"); public static final DamageSource ZAP_APPLE = create("zap"); public static DamageSource mundane(String type) { diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 22abe86f..05c8e2bb 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -21,6 +21,41 @@ "item.unicopia.music_disc_funk": "Music Disc", "item.unicopia.music_disc_funk.desc": "funk, just funk", + "unicopia.effect.tribe.stage.initial": "It appears to have no effect.", + "unicopia.effect.tribe.stage.crawling": "You feel the skin crawling on your back.", + "unicopia.effect.tribe.stage.determination": "As your bones realign you are filled determination.", + "unicopia.effect.tribe.stage.resurection": "Knowing you will return to this world as a %s", + + "effect.unicopia.change_race_earth": "Earth Pony Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_earth": "Potion of Earth Pony Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_earth": "Splash Potion of Earth Pony Metamorphosis", + "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_earth": "Lingering Potion of Earth Pony Metamorphosis", + "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_earth": "Arrow of Earth Pony Metamorphosis", + + "effect.unicopia.change_race_unicorn": "Unicorn Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_unicorn": "Potion of Unicorn Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_unicorn": "Splash Potion of Unicorn Metamorphosis", + "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_unicorn": "Lingering Potion of Unicorn Metamorphosis", + "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_unicorn": "Arrow of Unicorn Metamorphosis", + + "effect.unicopia.change_race_pegasus": "Pegasus Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_pegasus": "Potion of Pegasus Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_pegasus": "Splash Potion of Pegasus Metamorphosis", + "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_pegasus": "Lingering Potion of Pegasus Metamorphosis", + "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_pegasus": "Arrow of Pegasus Metamorphosis", + + "effect.unicopia.change_race_changeling": "Changeling Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_changeling": "Potion of Changeling Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_changeling": "Splash Potion of Changeling Metamorphosis", + "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_changeling": "Lingering Potion of Changeling Metamorphosis", + "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_changeling": "Arrow of Changeling Metamorphosis", + + "effect.unicopia.change_race_bat": "Bat Pony Metamorphosis", + "item.minecraft.potion.effect.unicopia.tribe_swap_bat": "Potion of Bat Pony Metamorphosis", + "item.minecraft.splash_potion.effect.unicopia.tribe_swap_bat": "Splash 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", + "affinity.good": "Pure", "affinity.neutral": "Neutral", "affinity.curse": "Corrupt", @@ -178,6 +213,7 @@ "key.unicopia.tertiary": "Tertiary Ability", "key.unicopia.passive": "Passive Ability", + "death.attack.tribe_swap": "%1$s was reborn into a different tribe", "death.attack.magical_exhaustion": "%1$s exhausted themselves", "death.attack.alicorn_amulet": "%1$s was driven insane", "death.attack.darkness": "%1$s went missing",