diff --git a/HOW_TO_PLAY_CN.md b/HOW_TO_PLAY_CN.md index 0d839eea..93ae652b 100644 --- a/HOW_TO_PLAY_CN.md +++ b/HOW_TO_PLAY_CN.md @@ -124,6 +124,6 @@ 这些状态是按周期循环的,如果您发现的果树不是您想要的状态,可以在它旁边等待几天直到结果,但请不要在魔虹苹果成熟前收获它们,否则它们会把您电得酥脆! 如果您设法获取到了魔虹苹果的木头和叶子,那它们也可以充当威慑滋事者的完美屏障。 -### 马芬 +### 玛芬 香软可口,猪猪最爱。 \ No newline at end of file diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..6ff71f04 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: src/main/resources/assets/unicopia/lang/en_us.json + translation: /%original_path%/%locale_with_underscore%.%file_extension% diff --git a/gradle.properties b/gradle.properties index 017657b1..3ca5c348 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,7 +23,7 @@ org.gradle.daemon=false fabwork_version=1.3.0+1.20.2 modmenu_version=8.0.0-beta.1 minelp_version=4.11.6+1.20.2 - kirin_version=1.16.0+1.20.2 + kirin_version=1.16.1+1.20.2 reach_attributes_version=2.3.4 trinkets_version=3.8.0 terraformer_api_version=8.0.0-beta.1 diff --git a/src/main/java/com/minelittlepony/unicopia/Affinity.java b/src/main/java/com/minelittlepony/unicopia/Affinity.java index 35285a76..4265c0f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/Affinity.java +++ b/src/main/java/com/minelittlepony/unicopia/Affinity.java @@ -1,12 +1,18 @@ package com.minelittlepony.unicopia; -import net.minecraft.util.Formatting; +import java.util.Locale; -public enum Affinity { +import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; + +public enum Affinity implements StringIdentifiable { GOOD(Formatting.BLUE, -1, 0), NEUTRAL(Formatting.LIGHT_PURPLE, 0, 0.5F), BAD(Formatting.RED, 1, 1); + @SuppressWarnings("deprecation") + public static final EnumCodec CODEC = StringIdentifiable.createCodec(Affinity::values); + private final Formatting color; private final int corruption; @@ -20,6 +26,11 @@ public enum Affinity { this.alignment = alignment; } + @Override + public String asString() { + return name().toLowerCase(Locale.ROOT); + } + public Formatting getColor() { return color; } diff --git a/src/main/java/com/minelittlepony/unicopia/Availability.java b/src/main/java/com/minelittlepony/unicopia/Availability.java index f24497a3..716f61cb 100644 --- a/src/main/java/com/minelittlepony/unicopia/Availability.java +++ b/src/main/java/com/minelittlepony/unicopia/Availability.java @@ -1,10 +1,24 @@ package com.minelittlepony.unicopia; -public enum Availability { +import java.util.Locale; + +import net.minecraft.util.StringIdentifiable; + +public enum Availability implements StringIdentifiable { DEFAULT, COMMANDS, NONE; + @SuppressWarnings("deprecation") + public static final EnumCodec CODEC = StringIdentifiable.createCodec(Availability::values); + + private final String name = name().toLowerCase(Locale.ROOT); + + @Override + public String asString() { + return name; + } + public boolean isSelectable() { return this == DEFAULT; } diff --git a/src/main/java/com/minelittlepony/unicopia/Config.java b/src/main/java/com/minelittlepony/unicopia/Config.java index 8ccae93c..af798840 100644 --- a/src/main/java/com/minelittlepony/unicopia/Config.java +++ b/src/main/java/com/minelittlepony/unicopia/Config.java @@ -34,6 +34,9 @@ public class Config extends com.minelittlepony.common.util.settings.Config { .addComment("If true Mine Little Pony will not be considered when determining the race to use") .addComment("The result will always be what is set by this config file."); + public final Setting toggleAbilityKeys = value("client", "toggleAbilityKeys", false) + .addComment("If true the ability keybinds will function as toggle keys rather than hold keys"); + public final Setting hudPage = value("client", "hudActivePage", 0) .addComment("The page of abilities currently visible in the HUD. You can change this in-game using the PG_UP and PG_DWN keys (configurable)"); diff --git a/src/main/java/com/minelittlepony/unicopia/FlightType.java b/src/main/java/com/minelittlepony/unicopia/FlightType.java index f2ef92f0..b26d272e 100644 --- a/src/main/java/com/minelittlepony/unicopia/FlightType.java +++ b/src/main/java/com/minelittlepony/unicopia/FlightType.java @@ -1,15 +1,28 @@ package com.minelittlepony.unicopia; +import java.util.Locale; + import net.minecraft.entity.player.PlayerEntity; import net.minecraft.sound.SoundEvent; +import net.minecraft.util.StringIdentifiable; -public enum FlightType { +public enum FlightType implements StringIdentifiable { UNSET, NONE, AVIAN, INSECTOID, ARTIFICIAL; + @SuppressWarnings("deprecation") + public static final EnumCodec CODEC = StringIdentifiable.createCodec(FlightType::values); + + private final String name = name().toLowerCase(Locale.ROOT); + + @Override + public String asString() { + return name; + } + public boolean isGrounded() { return this == NONE; } diff --git a/src/main/java/com/minelittlepony/unicopia/Owned.java b/src/main/java/com/minelittlepony/unicopia/Owned.java index 47c5403c..41c55d02 100644 --- a/src/main/java/com/minelittlepony/unicopia/Owned.java +++ b/src/main/java/com/minelittlepony/unicopia/Owned.java @@ -53,7 +53,7 @@ public interface Owned { } default boolean hasCommonOwner(Owned sibling) { - return getMasterId().isPresent() && getMasterId().equals(sibling.getMasterId()); + return getMasterId().equals(sibling.getMasterId()); } interface Mutable { diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index dd3bf4d9..9c02ecdb 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -1,20 +1,21 @@ package com.minelittlepony.unicopia; import java.util.*; +import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; -import org.spongepowered.include.com.google.common.base.Objects; - import com.google.common.base.Strings; -import com.google.common.base.Suppliers; +import com.minelittlepony.unicopia.ability.Abilities; +import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.util.RegistryUtils; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.command.argument.RegistryKeyArgumentType; import net.minecraft.entity.player.PlayerEntity; @@ -22,52 +23,89 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.util.Util; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; -public record Race (Supplier compositeSupplier, Availability availability, boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) implements Affine { +public record Race ( + List> abilities, + Affinity affinity, + Availability availability, + FlightType flightType, + boolean canCast, + boolean hasIronGut, + boolean canUseEarth, + boolean isNocturnal, + boolean canHang, + boolean isFish, + boolean canInfluenceWeather, + boolean canInteractWithClouds + ) implements Affine { public static final String DEFAULT_ID = "unicopia:unset"; public static final Registry REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final Registry COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID); public static final RegistryKey> REGISTRY_KEY = REGISTRY.getKey(); - private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("race.unknown", id)); + private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("commands.race.fail", id)); + private static final Function COMPOSITES = Util.memoize(race -> new Composite(race, null, null)); - public static Race register(String name, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { - return register(Unicopia.id(name), availability, magic, flight, earth, nocturnal, canHang); - } - - public static Race register(Identifier id, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { - Race race = Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null, null)), availability, magic, flight, earth, nocturnal, canHang)); - if (availability.isGrantable()) { - Registry.register(COMMAND_REGISTRY, id, race); - } - return race; - } - - public static RegistryKeyArgumentType argument() { - return RegistryKeyArgumentType.registryKey(COMMAND_REGISTRY.getKey()); - } + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Abilities.REGISTRY.getCodec().listOf().fieldOf("abilities").forGetter(Race::abilities), + Affinity.CODEC.fieldOf("affinity").forGetter(Race::affinity), + Availability.CODEC.fieldOf("availability").forGetter(Race::availability), + FlightType.CODEC.fieldOf("flight").forGetter(Race::flightType), + Codec.BOOL.fieldOf("magic").forGetter(Race::canCast), + Codec.BOOL.fieldOf("can_forage").forGetter(Race::hasIronGut), + Codec.BOOL.fieldOf("earth_pony_strength").forGetter(Race::canUseEarth), + Codec.BOOL.fieldOf("nocturnal").forGetter(Race::isNocturnal), + Codec.BOOL.fieldOf("hanging").forGetter(Race::canHang), + Codec.BOOL.fieldOf("aquatic").forGetter(Race::isFish), + Codec.BOOL.fieldOf("weather_magic").forGetter(Race::canInfluenceWeather), + Codec.BOOL.fieldOf("cloud_magic").forGetter(Race::canInteractWithClouds) + ).apply(i, Race::new)); /** * The default, unset race. * This is used if there are no other races. */ - public static final Race UNSET = register("unset", Availability.COMMANDS, false, FlightType.NONE, false, false, false); - public static final Race HUMAN = register("human", Availability.COMMANDS, false, FlightType.NONE, false, false, false); - public static final Race EARTH = register("earth", Availability.DEFAULT, false, FlightType.NONE, true, false, false); - public static final Race UNICORN = register("unicorn", Availability.DEFAULT, true, FlightType.NONE, false, false, false); - public static final Race PEGASUS = register("pegasus", Availability.DEFAULT, false, FlightType.AVIAN, false, false, false); - public static final Race BAT = register("bat", Availability.DEFAULT, false, FlightType.AVIAN, false, true, true); - public static final Race ALICORN = register("alicorn", Availability.COMMANDS, true, FlightType.AVIAN, true, false, false); - public static final Race CHANGELING = register("changeling", Availability.DEFAULT, false, FlightType.INSECTOID, false, false, true); - public static final Race KIRIN = register("kirin", Availability.DEFAULT, true, FlightType.NONE, false, false, false); - public static final Race HIPPOGRIFF = register("hippogriff", Availability.DEFAULT, false, FlightType.AVIAN, false, false, false); - public static final Race SEAPONY = register("seapony", Availability.NONE, false, FlightType.NONE, false, false, false); + public static final Race UNSET = register("unset", new Builder().availability(Availability.COMMANDS)); + public static final Race HUMAN = register("human", new Builder().availability(Availability.COMMANDS)); + public static final Race EARTH = register("earth", new Builder().foraging().earth() + .abilities(Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW) + ); + public static final Race UNICORN = register("unicorn", new Builder().foraging().magic() + .abilities(Abilities.TELEPORT, Abilities.CAST, Abilities.GROUP_TELEPORT, Abilities.SHOOT, Abilities.DISPELL) + ); + public static final Race PEGASUS = register("pegasus", new Builder().foraging().flight(FlightType.AVIAN).weatherMagic().cloudMagic() + .abilities(Abilities.TOGGLE_FLIGHT, Abilities.RAINBOOM, Abilities.CAPTURE_CLOUD, Abilities.CARRY) + ); + public static final Race BAT = register("bat", new Builder().foraging().flight(FlightType.AVIAN).canHang().cloudMagic() + .abilities(Abilities.TOGGLE_FLIGHT, Abilities.CARRY, Abilities.HANG, Abilities.EEEE) + ); + public static final Race ALICORN = register("alicorn", new Builder().foraging().availability(Availability.COMMANDS).flight(FlightType.AVIAN).earth().magic().weatherMagic().cloudMagic() + .abilities( + Abilities.TELEPORT, Abilities.GROUP_TELEPORT, Abilities.CAST, Abilities.SHOOT, Abilities.DISPELL, + Abilities.TOGGLE_FLIGHT, Abilities.RAINBOOM, Abilities.CAPTURE_CLOUD, Abilities.CARRY, + Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW, + Abilities.TIME + ) + ); + public static final Race CHANGELING = register("changeling", new Builder().foraging().affinity(Affinity.BAD).flight(FlightType.INSECTOID).canHang() + .abilities(Abilities.DISPELL, Abilities.TOGGLE_FLIGHT, Abilities.FEED, Abilities.DISGUISE, Abilities.CARRY) + ); + public static final Race KIRIN = register("kirin", new Builder().foraging().magic() + .abilities(Abilities.DISPELL, Abilities.RAGE, Abilities.NIRIK_BLAST, Abilities.KIRIN_CAST) + ); + public static final Race HIPPOGRIFF = register("hippogriff", new Builder().foraging().flight(FlightType.AVIAN).cloudMagic() + .abilities(Abilities.TOGGLE_FLIGHT, Abilities.SCREECH, Abilities.PECK, Abilities.DASH, Abilities.CARRY) + ); + public static final Race SEAPONY = register("seapony", new Builder().availability(Availability.COMMANDS).foraging().fish() + .abilities(Abilities.SONAR_PULSE) + ); public static void bootstrap() {} public Composite composite() { - return compositeSupplier.get(); + return COMPOSITES.apply(this); } public Composite composite(@Nullable Race pseudo, @Nullable Race potential) { @@ -76,11 +114,7 @@ public record Race (Supplier compositeSupplier, Availability availabi @Override public Affinity getAffinity() { - return this == CHANGELING ? Affinity.BAD : Affinity.NEUTRAL; - } - - public boolean hasIronGut() { - return !isHuman(); + return affinity; } public boolean isUnset() { @@ -91,12 +125,8 @@ public record Race (Supplier compositeSupplier, Availability availabi return !isHuman(); } - public boolean isFish() { - return this == SEAPONY; - } - public boolean isHuman() { - return this == UNSET || this == HUMAN; + return isUnset() || this == HUMAN; } public boolean isDayurnal() { @@ -107,18 +137,14 @@ public record Race (Supplier compositeSupplier, Availability availabi return !flightType().isGrounded(); } - public boolean canInteractWithClouds() { - return canFly() && this != CHANGELING; - } - - public boolean canInfluenceWeather() { - return canFly() && this != CHANGELING && this != BAT && this != HIPPOGRIFF; - } - public boolean hasPersistentWeatherMagic() { return canInfluenceWeather(); } + public boolean canUse(Ability ability) { + return abilities.contains(ability); + } + public Identifier getId() { return REGISTRY.getId(this); } @@ -132,13 +158,11 @@ public record Race (Supplier compositeSupplier, Availability availabi } public String getTranslationKey() { - Identifier id = getId(); - return String.format("%s.race.%s", id.getNamespace(), id.getPath().toLowerCase()); + return Util.createTranslationKey("race", getId()); } public Identifier getIcon() { - Identifier id = getId(); - return new Identifier(id.getNamespace(), "textures/gui/race/" + id.getPath() + ".png"); + return getId().withPath(p -> "textures/gui/race/" + p + ".png"); } public boolean isPermitted(@Nullable PlayerEntity sender) { @@ -161,16 +185,6 @@ public record Race (Supplier compositeSupplier, Availability availabi return isEquine() ? this : other; } - @Override - public int hashCode() { - return getId().hashCode(); - } - - @Override - public boolean equals(Object o) { - return o instanceof Race race && Objects.equal(race.getId(), getId()); - } - @Override public String toString() { return "Race{ " + getId().toString() + " }"; @@ -195,13 +209,29 @@ public record Race (Supplier compositeSupplier, Availability availabi return def; } - public static Race fromName(String name) { - return fromName(name, EARTH); + public static Race register(String name, Builder builder) { + return register(Unicopia.id(name), builder); + } + + public static Race register(Identifier id, Builder builder) { + Race race = Registry.register(REGISTRY, id, builder.build()); + if (race.availability().isGrantable()) { + Registry.register(COMMAND_REGISTRY, id, race); + } + return race; + } + + public static RegistryKeyArgumentType argument() { + return RegistryKeyArgumentType.registryKey(COMMAND_REGISTRY.getKey()); } public static Race fromArgument(CommandContext context, String name) throws CommandSyntaxException { Identifier id = context.getArgument(name, RegistryKey.class).getValue(); - return REGISTRY.getOrEmpty(id).orElseThrow(() -> UNKNOWN_RACE_EXCEPTION.create(id)); + final Identifier idf = id; + if (id.getNamespace() == Identifier.DEFAULT_NAMESPACE && !REGISTRY.containsId(id)) { + id = new Identifier(REGISTRY_KEY.getValue().getNamespace(), id.getPath()); + } + return REGISTRY.getOrEmpty(id).orElseThrow(() -> UNKNOWN_RACE_EXCEPTION.create(idf)); } public static Set allPermitted(PlayerEntity player) { @@ -233,6 +263,10 @@ public record Race (Supplier compositeSupplier, Availability availabi return any(Race::canCast); } + public boolean canUse(Ability ability) { + return any(r -> r.canUse(ability)); + } + public boolean canInteractWithClouds() { return any(Race::canInteractWithClouds); } @@ -252,6 +286,85 @@ public record Race (Supplier compositeSupplier, Availability availabi return physical().flightType().or(pseudo().flightType()); } } + + public static final class Builder { + private final List> abilities = new ArrayList<>(); + private Affinity affinity = Affinity.NEUTRAL; + private Availability availability = Availability.DEFAULT; + private boolean canCast; + private boolean hasIronGut; + private FlightType flightType = FlightType.NONE; + private boolean canUseEarth; + private boolean isNocturnal; + private boolean canHang; + private boolean isFish; + private boolean canInfluenceWeather; + private boolean canInteractWithClouds; + + public Builder abilities(Ability...abilities) { + this.abilities.addAll(List.of(abilities)); + return this; + } + + public Builder foraging() { + hasIronGut = true; + return this; + } + + public Builder affinity(Affinity affinity) { + this.affinity = affinity; + return this; + } + + public Builder availability(Availability availability) { + this.availability = availability; + return this; + } + + public Builder flight(FlightType flight) { + flightType = flight; + return this; + } + + public Builder magic() { + canCast = true; + return this; + } + + public Builder earth() { + canUseEarth = true; + return this; + } + + public Builder nocturnal() { + isNocturnal = true; + return this; + } + + public Builder canHang() { + canHang = true; + return this; + } + + public Builder fish() { + isFish = true; + return this; + } + + public Builder weatherMagic() { + canInfluenceWeather = true; + return this; + } + + public Builder cloudMagic() { + canInteractWithClouds = true; + return this; + } + + public Race build() { + return new Race(List.copyOf(abilities), affinity, availability, flightType, canCast, hasIronGut, canUseEarth, isNocturnal, canHang, isFish, canInfluenceWeather, canInteractWithClouds); + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/WeaklyOwned.java b/src/main/java/com/minelittlepony/unicopia/WeaklyOwned.java index 514c22fd..504191bf 100644 --- a/src/main/java/com/minelittlepony/unicopia/WeaklyOwned.java +++ b/src/main/java/com/minelittlepony/unicopia/WeaklyOwned.java @@ -42,8 +42,8 @@ public interface WeaklyOwned extends Owned, WorldConvertabl @Override @SuppressWarnings("unchecked") default void setMaster(Owned sibling) { - if (sibling instanceof WeaklyOwned) { - getMasterReference().copyFrom(((WeaklyOwned)sibling).getMasterReference()); + if (sibling instanceof WeaklyOwned w) { + getMasterReference().copyFrom(w.getMasterReference()); } else { setMaster(sibling.getMaster()); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java index 979d7f97..eaa96379 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java @@ -68,7 +68,9 @@ public interface Ability { * Checks if the given race is permitted to use this ability * @param playerSpecies The player's species */ - boolean canUse(Race playerSpecies); + default boolean canUse(Race race) { + return race.canUse(this); + } /** * Called when an ability is about to be triggered. This event occurs on both the client and server so check {@code Pony#isClient} if you need to know which one you're on. diff --git a/src/main/java/com/minelittlepony/unicopia/ability/AbstractSpellCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/AbstractSpellCastingAbility.java index 2ff33f62..abe2489e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/AbstractSpellCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/AbstractSpellCastingAbility.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.ability; -import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.entity.player.Pony; @@ -11,17 +10,11 @@ import net.minecraft.util.ActionResult; import net.minecraft.util.TypedActionResult; abstract class AbstractSpellCastingAbility implements Ability { - @Override public int getCooldownTime(Pony player) { return 0; } - @Override - public boolean canUse(Race race) { - return race.canCast() && race != Race.KIRIN; - } - @Override public Text getName(Pony player) { CustomisedSpellType spell = player.getCharms().getEquippedSpell(player.getCharms().getHand()); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java index 0b0d1b4e..5222ac16 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.ability; import com.minelittlepony.unicopia.AwaitTickQueue; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; @@ -16,11 +15,6 @@ import net.minecraft.world.event.GameEvent; public class BatEeeeAbility extends ScreechAbility { public static final int SELF_SPOOK_PROBABILITY = 20000; - @Override - public boolean canUse(Race race) { - return race == Race.BAT; - } - @Override protected void playSounds(Pony player, Random rng, float strength) { int count = 1 + rng.nextInt(10) + (int)(strength * 10); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java index 9237ab34..723cc0f5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability; import java.util.Optional; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Multi; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.TraceHelper; @@ -30,11 +29,6 @@ public class BatPonyHangAbility implements Ability { return 0; } - @Override - public boolean canUse(Race race) { - return race == Race.BAT; - } - @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java index e93d1c2a..844fd96f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java @@ -6,7 +6,6 @@ import java.util.UUID; import java.util.stream.StreamSupport; import com.minelittlepony.unicopia.EquinePredicates; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.player.Pony; @@ -37,11 +36,6 @@ public class CarryAbility implements Ability { return 0; } - @Override - public boolean canUse(Race race) { - return race.canFly(); - } - @Override public Optional prepare(Pony player) { return Hit.INSTANCE; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java index 7a4e1f76..974f212c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java @@ -7,7 +7,6 @@ import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; @@ -48,11 +47,6 @@ public class ChangelingFeedAbility implements Ability { return !SpellType.FEED.isOn(player) && ChangelingFeedingSpell.canFeed(player) ? 15 : 80; } - @Override - public boolean canUse(Race race) { - return race == Race.CHANGELING; - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java index a4883de9..bb9b49e4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java @@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability; import java.util.Optional; import java.util.function.DoubleSupplier; import java.util.function.Supplier; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.data.Hit; @@ -48,11 +47,6 @@ public class EarthPonyGrowAbility implements Ability { return 50; } - @Override - public boolean canUse(Race race) { - return race.canUseEarth(); - } - @Override public Optional prepare(Pony player) { return TraceHelper.findBlock(player.asEntity(), 3, 1).map(Pos::new); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java index 0affd0cf..62dfda4a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java @@ -53,11 +53,6 @@ public class EarthPonyKickAbility implements Ability { return 50; } - @Override - public boolean canUse(Race race) { - return race.canUseEarth(); - } - @Override public Identifier getIcon(Pony player) { return getId().withPath(p -> "textures/gui/ability/" + p diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index 285266c9..78314ba7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -62,11 +62,6 @@ public class EarthPonyStompAbility implements Ability { return 50; } - @Override - public boolean canUse(Race race) { - return race.canUseEarth(); - } - @Override public Identifier getIcon(Pony player) { Identifier id = Abilities.REGISTRY.getId(this); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java index 0a9f5f6b..c9436ce9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/FlyingDashAbility.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.entity.player.Pony; @@ -23,11 +22,6 @@ public class FlyingDashAbility implements Ability { return 30; } - @Override - public boolean canUse(Race race) { - return race == Race.HIPPOGRIFF; - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/HugAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/HugAbility.java index 6457ccb9..caca424f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/HugAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/HugAbility.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.ability; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.Living; @@ -16,12 +15,6 @@ import net.minecraft.particle.ParticleTypes; * Ability to hug mobs. Not all of them are receptive to your advances though, so be careful! */ public class HugAbility extends CarryAbility { - - @Override - public boolean canUse(Race race) { - return race.canUseEarth(); - } - @Override public boolean apply(Pony pony, Hit data) { PlayerEntity player = pony.asEntity(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/KirinCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/KirinCastingAbility.java index 5b82e4cc..53b2e56c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/KirinCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/KirinCastingAbility.java @@ -1,16 +1,10 @@ package com.minelittlepony.unicopia.ability; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.particle.ParticleTypes; public class KirinCastingAbility extends UnicornCastingAbility { - @Override - public boolean canUse(Race race) { - return race == Race.KIRIN; - } - @Override public void coolDown(Pony player, AbilitySlot slot) { player.spawnParticles(ParticleTypes.FLAME, 5); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/KirinRageAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/KirinRageAbility.java index 92d0074c..dce16e46 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/KirinRageAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/KirinRageAbility.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; @@ -30,11 +29,6 @@ public class KirinRageAbility implements Ability { return 60; } - @Override - public boolean canUse(Race race) { - return race == Race.KIRIN; - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java index 3c516f32..65c6f353 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/NirikBlastAbility.java @@ -5,7 +5,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.EquinePredicates; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; @@ -36,11 +35,6 @@ public class NirikBlastAbility implements Ability { return 3; } - @Override - public boolean canUse(Race race) { - return race == Race.KIRIN; - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java index 849dbb4c..db5b09fc 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/PeckAbility.java @@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability; import java.util.Optional; import com.minelittlepony.unicopia.EquinePredicates; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Numeric; @@ -54,11 +53,6 @@ public class PeckAbility implements Ability { return true; } - @Override - public boolean canUse(Race race) { - return race == Race.HIPPOGRIFF; - } - @Override public Optional prepare(Pony player) { return Hit.INSTANCE; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusCaptureStormAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PegasusCaptureStormAbility.java index b02579df..6b59dfe4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusCaptureStormAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/PegasusCaptureStormAbility.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.UItems; @@ -33,11 +32,6 @@ public class PegasusCaptureStormAbility implements Ability { return 6; } - @Override - public boolean canUse(Race race) { - return race.canInfluenceWeather(); - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java index 606cd65f..c9abd9b6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; @@ -26,11 +25,6 @@ public class PegasusRainboomAbility implements Ability { return 60; } - @Override - public boolean canUse(Race race) { - return race.canInfluenceWeather(); - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java index b4dc2eb4..53c8b702 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java @@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability; import java.util.Optional; import com.minelittlepony.unicopia.EquinePredicates; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.data.Numeric; @@ -49,11 +48,6 @@ public class ScreechAbility implements Ability { return true; } - @Override - public boolean canUse(Race race) { - return race == Race.HIPPOGRIFF; - } - @Override public Optional prepare(Pony player) { return player.getAbilities().getActiveStat() diff --git a/src/main/java/com/minelittlepony/unicopia/ability/SeaponySonarPulseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/SeaponySonarPulseAbility.java index 95078776..f1be14f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/SeaponySonarPulseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/SeaponySonarPulseAbility.java @@ -5,7 +5,6 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.AwaitTickQueue; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.UPOIs; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; @@ -38,11 +37,6 @@ public class SeaponySonarPulseAbility implements Ability { return 100; } - @Override - public boolean canUse(Race race) { - return race == Race.SEAPONY; - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java index a1e92a03..b06df709 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/TimeChangeAbility.java @@ -12,11 +12,6 @@ import com.minelittlepony.unicopia.server.world.UGameRules; public class TimeChangeAbility implements Ability { - @Override - public boolean canUse(Race race) { - return race == Race.ALICORN; - } - @Override public boolean canUse(Race.Composite race) { return canUse(race.physical()) || race.pseudo() == Race.UNICORN; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java index 4f20d77d..caa3c701 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java @@ -24,11 +24,6 @@ public class ToggleFlightAbility implements Ability { return 0; } - @Override - public boolean canUse(Race race) { - return race.canFly(); - } - @Nullable @Override public Optional prepare(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java index d965f9da..7b0c35d6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornDispellAbility.java @@ -33,11 +33,6 @@ public class UnicornDispellAbility implements Ability { return 0; } - @Override - public boolean canUse(Race race) { - return race.canCast() || race == Race.CHANGELING; - } - @Override public int getColor(Pony player) { return SpellType.PORTAL.getColor(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java index 8b64862f..39cc5763 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability; import java.util.Optional; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; @@ -60,11 +59,6 @@ public class UnicornTeleportAbility implements Ability { return (int)(50 - Math.min(45F, player.getLevel().get() * 0.75F)); } - @Override - public boolean canUse(Race race) { - return race.canCast() && race != Race.KIRIN; - } - @Override public double getCostEstimate(Pony player) { return prepare(player).map(pos -> pos.distanceTo(player) / 10).orElse(0D); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 51c26ea8..9f179443 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -98,7 +98,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public boolean isDead() { - return dead && deathTicks <= 0; + return dead && deathTicks <= 0 && super.isDead(); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java index ea5f8462..e46941c0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java @@ -1,8 +1,12 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.Optional; + import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.USounds; +import com.minelittlepony.unicopia.UTags; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; @@ -12,6 +16,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; +import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; @@ -19,13 +24,17 @@ import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.projectile.MagicBeamEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; +import com.minelittlepony.unicopia.server.world.UGameRules; +import com.minelittlepony.unicopia.util.Lerp; import com.minelittlepony.unicopia.util.shape.Sphere; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; -import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.PersistentProjectileEntity; import net.minecraft.item.Item; +import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; @@ -39,7 +48,7 @@ import net.minecraft.world.World.ExplosionSourceType; /** * More powerful version of the vortex spell which creates a black hole. */ -public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelegate.BlockHitListener { +public class DarkVortexSpell extends AbstractSpell implements ProjectileDelegate.BlockHitListener { public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() .with(Trait.CHAOS, 5) .with(Trait.KNOWLEDGE, 1) @@ -49,18 +58,31 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega private float accumulatedMass = 0; + private final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget).setTargetowner(true).setTargetAllies(true); + + private final Lerp radius = new Lerp(0); + protected DarkVortexSpell(CustomisedSpellType type) { super(type); - targetSelecter.setTargetowner(true).setTargetAllies(true); + } + // 1. force decreases with distance: distance scale 1 -> 0 + // 2. max force (at dist 0) is taken from accumulated mass + // 3. force reaches 0 at distance of drawDropOffRange + + private double getMass() { + return 0.1F + accumulatedMass / 10F; } - @Override - public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { - if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) { - BlockPos pos = hit.getBlockPos(); - projectile.getWorld().createExplosion(projectile, pos.getX(), pos.getY(), pos.getZ(), 3, ExplosionSourceType.NONE); - toPlaceable().tick(source, Situation.BODY); - } + public double getEventHorizonRadius() { + return radius.getValue(); + } + + public double getDrawDropOffRange() { + return getEventHorizonRadius() * 20; + } + + private double getAttractiveForce(Caster source, Entity target) { + return AttractionUtils.getAttractiveForce(getMass(), getOrigin(source), target); } @Override @@ -79,22 +101,102 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega return true; } + Vec3d origin = getOrigin(source); + double mass = getMass() * 0.1; + double logarithm = 1 - (1D / (1 + (mass * mass))); + radius.update((float)Math.max(0.01, logarithm * source.asWorld().getGameRules().getInt(UGameRules.MAX_DARK_VORTEX_SIZE)), 200L); + if (source.asEntity().age % 20 == 0) { source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_ADDITIONS, SoundCategory.AMBIENT, 1, 1); } - if (!source.isClient() && source.asWorld().random.nextInt(300) == 0) { - ParticleUtils.spawnParticle(source.asWorld(), LightningBoltParticleEffect.DEFAULT, getOrigin(source), Vec3d.ZERO); + double eventHorizon = getEventHorizonRadius(); + + if (source.isClient()) { + if (eventHorizon > 0.3) { + double range = eventHorizon * 2; + source.spawnParticles(origin, new Sphere(false, range), 50, p -> { + source.addParticle( + new FollowingParticleEffect(UParticles.HEALTH_DRAIN, origin, 0.4F) + .withChild(source.asWorld().isAir(BlockPos.ofFloored(p)) ? ParticleTypes.SMOKE : ParticleTypes.CAMPFIRE_SIGNAL_SMOKE), + p, + Vec3d.ZERO + ); + }); + } + + if (source.asWorld().random.nextInt(300) == 0) { + ParticleUtils.spawnParticle(source.asWorld(), LightningBoltParticleEffect.DEFAULT, origin, Vec3d.ZERO); + } + } else { + if (eventHorizon > 2) { + new Sphere(false, eventHorizon + 3).translate(origin).randomPoints(10, source.asWorld().random).forEach(i -> { + BlockPos pos = BlockPos.ofFloored(i); + if (!source.asWorld().isAir(pos)) { + new Sphere(false, 3).translate(i).getBlockPositions().forEach(p -> { + affectBlock(source, p, origin); + }); + ParticleUtils.spawnParticle(source.asWorld(), new LightningBoltParticleEffect(true, 10, 6, 3, Optional.of(i)), getOrigin(source), Vec3d.ZERO); + } + }); + } + } + + + for (Entity insideEntity : source.findAllEntitiesInRange(eventHorizon * 0.5F).toList()) { + insideEntity.setVelocity(Vec3d.ZERO); + Living.updateVelocity(insideEntity); + + if (insideEntity instanceof CastSpellEntity s && getType().isOn(insideEntity)) { + setDead(); + s.getSpellSlot().clear(); + source.asWorld().createExplosion(source.asEntity(), origin.x, origin.y, origin.z, 12, ExplosionSourceType.NONE); + source.asWorld().createExplosion(source.asEntity(), insideEntity.getX(), insideEntity.getY(), insideEntity.getZ(), 12, ExplosionSourceType.NONE); + return false; + } + } + targetSelecter.getEntities(source, getDrawDropOffRange()).forEach(i -> { + try { + affectEntity(source, i, origin); + } catch (Throwable e) { + Unicopia.LOGGER.error("Error updating radial effect", e); + } + }); + + if (!source.subtractEnergyCost(0.01)) { + setDead(); + source.asWorld().createExplosion(source.asEntity(), origin.x, origin.y, origin.z, 3, ExplosionSourceType.NONE); } - super.tick(source, situation); return true; } + @Override - protected void consumeManage(Caster source, long costMultiplier, float knowledge) { - if (!source.subtractEnergyCost(-accumulatedMass)) { - setDead(); + public void tickDying(Caster source) { + accumulatedMass -= 0.8F; + double mass = getMass() * 0.1; + double logarithm = 1 - (1D / (1 + (mass * mass))); + radius.update((float)Math.max(0.1, logarithm * source.asWorld().getGameRules().getInt(UGameRules.MAX_DARK_VORTEX_SIZE)), 200L); + if (accumulatedMass < 1) { + super.tickDying(source); + } + + Vec3d origin = getOrigin(source); + ParticleUtils.spawnParticle(source.asWorld(), ParticleTypes.SMOKE, origin, new Vec3d(0, 0.2F, 0)); + ParticleUtils.spawnParticle(source.asWorld(), ParticleTypes.SMOKE, origin, new Vec3d(0, -0.2F, 0)); + + if (!source.isClient() && source.asWorld().getRandom().nextInt(10) == 0) { + Block.dropStack(source.asWorld(), BlockPos.ofFloored(origin), (source.asWorld().getRandom().nextInt(75) == 0 ? Items.ANCIENT_DEBRIS : Items.IRON_NUGGET).getDefaultStack()); + } + } + + @Override + public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { + if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) { + Vec3d pos = hit.getPos(); + projectile.getWorld().createExplosion(projectile, pos.x, pos.y, pos.z, 12, ExplosionSourceType.NONE); + toPlaceable().tick(source, Situation.BODY); } } @@ -103,102 +205,54 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega return accumulatedMass < 4; } - @Override - protected boolean isValidTarget(Caster source, Entity entity) { + private boolean isValidTarget(Caster source, Entity entity) { return EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(entity) && getAttractiveForce(source, entity) > 0; } - @Override - public void generateParticles(Caster source) { - super.generateParticles(source); + public Vec3d getOrigin(Caster source) { + return source.asEntity().getPos().add(0, getYOffset(), 0); + } - if (getEventHorizonRadius() > 0.3) { - double range = getDrawDropOffRange(source); - Vec3d origin = getOrigin(source); - source.spawnParticles(origin, new Sphere(false, range), 1, p -> { - if (!source.asWorld().isAir(BlockPos.ofFloored(p))) { - source.addParticle( - new FollowingParticleEffect(UParticles.HEALTH_DRAIN, origin, 0.4F) - .withChild(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE), - p, - Vec3d.ZERO - ); - } + public double getYOffset() { + return 2; + } + + private boolean canAffect(Caster source, BlockPos pos) { + return source.canModifyAt(pos) + && source.asWorld().getBlockState(pos).getHardness(source.asWorld(), pos) >= 0 + && !source.asWorld().getBlockState(pos).isIn(UTags.Blocks.CATAPULT_IMMUNE); + } + + private void affectBlock(Caster source, BlockPos pos, Vec3d origin) { + if (!canAffect(source, pos)) { + if (source.asWorld().getBlockState(pos).isOf(Blocks.BEDROCK)) { + source.asWorld().setBlockState(pos, Blocks.BARRIER.getDefaultState()); + } + return; + } + if (pos.isWithinDistance(origin, getEventHorizonRadius())) { + source.asWorld().breakBlock(pos, false); + updateStatePostRemoval(source, pos); + } else { + CatapultSpell.createBlockEntity(source.asWorld(), pos, e -> { + updateStatePostRemoval(source, pos); + e.addVelocity(0, 0.1, 0); }); } } - @Override - public double getDrawDropOffRange(Caster source) { - return getEventHorizonRadius() * 20; - } - - @Override - protected Vec3d getOrigin(Caster source) { - return source.getOriginVector().add(0, getEventHorizonRadius() / 2D, 0); - } - - @Override - protected long applyEntities(Caster source) { - if (!source.isClient()) { - - double radius = getEventHorizonRadius(); - - if (radius > 2) { - Vec3d origin = getOrigin(source); - new Sphere(false, radius).translate(origin).getBlockPositions().forEach(i -> { - if (!canAffect(source, i)) { - return; - } - if (source.getOrigin().isWithinDistance(i, getEventHorizonRadius() / 2)) { - source.asWorld().breakBlock(i, false); - } else { - CatapultSpell.createBlockEntity(source.asWorld(), i, e -> { - applyRadialEffect(source, e, e.getPos().distanceTo(origin), radius); - }); - } - }); - } + private void updateStatePostRemoval(Caster source, BlockPos pos) { + if (!source.asWorld().getFluidState(pos).isEmpty()) { + source.asWorld().setBlockState(pos, Blocks.AIR.getDefaultState()); } - - return super.applyEntities(source); } - protected boolean canAffect(Caster source, BlockPos pos) { - return source.canModifyAt(pos) - && source.asWorld().getFluidState(pos).isEmpty() - && source.asWorld().getBlockState(pos).getHardness(source.asWorld(), pos) >= 0; - } + private void affectEntity(Caster source, Entity target, Vec3d origin) { + double distance = target.getPos().distanceTo(origin); + double eventHorizonRadius = getEventHorizonRadius(); - // 1. force decreases with distance: distance scale 1 -> 0 - // 2. max force (at dist 0) is taken from accumulated mass - // 3. force reaches 0 at distance of drawDropOffRange - - public double getEventHorizonRadius() { - return Math.sqrt(Math.max(0.001, getMass() / 3F)); - } - - private double getAttractiveForce(Caster source, Entity target) { - return AttractionUtils.getAttractiveForce(getMass(), getOrigin(source), target); - } - - private double getMass() { - return 0.1F + accumulatedMass / 10F; - } - - @Override - protected void applyRadialEffect(Caster source, Entity target, double distance, double radius) { - - if (target instanceof FallingBlockEntity && source.isClient()) { - return; - } - - if (distance <= getEventHorizonRadius() + 0.5) { - target.setVelocity(target.getVelocity().multiply(distance / (2 * radius))); - if (distance < 1) { - target.setVelocity(target.getVelocity().multiply(distance)); - - } + if (distance <= eventHorizonRadius + 0.5) { + target.setVelocity(target.getVelocity().multiply(distance < 1 ? distance : distance / (2 * eventHorizonRadius))); Living.updateVelocity(target); @Nullable @@ -227,20 +281,22 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega target.damage(source.damageOf(UDamageTypes.GAVITY_WELL_RECOIL, source), Integer.MAX_VALUE); if (!(target instanceof PlayerEntity)) { target.discard(); - source.asWorld().playSound(null, source.getOrigin(), USounds.ENCHANTMENT_CONSUMPTION_CONSUME, SoundCategory.AMBIENT, 2, 0.02F); + source.asWorld().playSound(null, target.getBlockPos(), USounds.AMBIENT_DARK_VORTEX_MOOD, SoundCategory.AMBIENT, 2, 0.002F); } if (target.isAlive()) { target.damage(source.asEntity().getDamageSources().outOfWorld(), Integer.MAX_VALUE); } source.subtractEnergyCost(-massOfTarget * 10); - source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_MOOD, SoundCategory.AMBIENT, 2, 0.02F); + + if (target instanceof PlayerEntity && distance < eventHorizonRadius + 5) { + source.asWorld().playSound(null, target.getBlockPos(), USounds.AMBIENT_DARK_VORTEX_MOOD, SoundCategory.AMBIENT, 2, 0.02F); + } + } else { double force = getAttractiveForce(source, target); - AttractionUtils.applyForce(getOrigin(source), target, -force, 0, true); - - source.subtractEnergyCost(-2); + AttractionUtils.applyForce(origin, target, -force, 0, true); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index 1e4243a6..dbf79bab 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -197,7 +197,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti } Equine.of(minion).filter(eq -> eq instanceof Creature).ifPresent(eq -> { - ((Creature)eq).setMaster(source.getMaster()); + ((Creature)eq).setMaster(source); if (source.asWorld().random.nextFloat() < source.getCorruption().getScaled(1)) { ((Creature)eq).setDiscorded(true); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index 82a66ad9..fea666b7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -57,7 +57,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme } public boolean isLinked() { - return teleportationTarget.getTarget().isPresent(); + return teleportationTarget.isSet(); } public Optional> getTarget() { @@ -85,7 +85,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme } @SuppressWarnings("unchecked") - private Optional> getTarget(Caster source) { + private Optional> getDestination(Caster source) { return getTarget().map(target -> Ether.get(source.asWorld()).get((SpellType)getType(), target, targetPortalId)); } @@ -98,13 +98,12 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme @Override public boolean tick(Caster source, Situation situation) { if (situation == Situation.GROUND) { - if (source.isClient()) { source.spawnParticles(particleArea, 5, pos -> { source.addParticle(ParticleTypes.ELECTRIC_SPARK, pos, Vec3d.ZERO); }); } else { - getTarget().ifPresent(target -> { + teleportationTarget.getTarget().ifPresent(target -> { if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) == null) { Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + target.uuid()); teleportationTarget.set(null); @@ -113,16 +112,17 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme } }); - getTarget(source).ifPresentOrElse( + getDestination(source).ifPresentOrElse( entry -> tickWithTargetLink(source, entry), () -> findLink(source) ); } - var entry = Ether.get(source.asWorld()).getOrCreate(this, source); + Ether ether = Ether.get(source.asWorld()); + var entry = ether.getOrCreate(this, source); entry.pitch = pitch; entry.yaw = yaw; - Ether.get(source.asWorld()).markDirty(); + ether.markDirty(); } return !isDead(); @@ -185,8 +185,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme } Ether.get(source.asWorld()).anyMatch(getType(), entry -> { - if (entry.isAvailable() && !entry.entity.referenceEquals(source.asEntity()) && entry.entity.isSet()) { - entry.setTaken(true); + if (!entry.entity.referenceEquals(source.asEntity()) && entry.claim()) { teleportationTarget.copyFrom(entry.entity); targetPortalId = entry.getSpellId(); setDirty(); @@ -216,9 +215,8 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme @Override protected void onDestroyed(Caster caster) { - Ether ether = Ether.get(caster.asWorld()); - ether.remove(getType(), caster); - getTarget(caster).ifPresent(e -> e.setTaken(false)); + Ether.get(caster.asWorld()).remove(getType(), caster); + getDestination(caster).ifPresent(Ether.Entry::release); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 90bbed43..e963c0e7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -1,10 +1,5 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.EnumMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Affinity; @@ -20,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; +import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.util.RegistryUtils; import com.mojang.brigadier.context.CommandContext; @@ -38,48 +34,47 @@ import net.minecraft.server.command.ServerCommandSource; public final class SpellType implements Affine, SpellPredicate { public static final Identifier EMPTY_ID = Unicopia.id("none"); - public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, SpellTraits.EMPTY, t -> null); + public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, GemstoneItem.Shape.ROUND, SpellTraits.EMPTY, t -> null); public static final Registry> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells")); public static final RegistryKey>> REGISTRY_KEY = REGISTRY.getKey(); - public static final Map>> BY_AFFINITY = new EnumMap<>(Affinity.class); private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); - public static final SpellType PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, PlaceableSpell::new); - public static final SpellType THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, ThrowableSpell::new); + public static final SpellType PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, PlaceableSpell::new); + public static final SpellType THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, ThrowableSpell::new); - public static final SpellType CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new); - public static final SpellType FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, SpellTraits.EMPTY, ChangelingFeedingSpell::new); - public static final SpellType RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new); - public static final SpellType RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new); - public static final SpellType TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new); + public static final SpellType CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, DispersableDisguiseSpell::new); + public static final SpellType FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, ChangelingFeedingSpell::new); + public static final SpellType RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, RainboomAbilitySpell::new); + public static final SpellType RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.FLAME, SpellTraits.EMPTY, RageAbilitySpell::new); + public static final SpellType TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.STAR, SpellTraits.EMPTY, TimeControlAbilitySpell::new); - public static final SpellType FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, IceSpell.DEFAULT_TRAITS, IceSpell::new); - public static final SpellType CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new); - public static final SpellType SCORCH = register("scorch", Affinity.BAD, 0xF8EC1F, true, ScorchSpell.DEFAULT_TRAITS, ScorchSpell::new); - public static final SpellType FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, FireSpell.DEFAULT_TRAITS, FireSpell::new); - public static final SpellType INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new); - public static final SpellType SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new); - public static final SpellType ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new); - public static final SpellType VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new); - public static final SpellType DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new); - public static final SpellType NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, SpellTraits.EMPTY, NecromancySpell::new); - public static final SpellType SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, SpellTraits.EMPTY, SiphoningSpell::new); - public static final SpellType REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, SpellTraits.EMPTY, DisperseIllusionSpell::new); - public static final SpellType AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, SpellTraits.EMPTY, AwkwardSpell::new); - public static final SpellType TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, SpellTraits.EMPTY, TransformationSpell::new); - public static final SpellType FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new); - public static final SpellType CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new); - public static final SpellType FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new); - public static final SpellType LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, LightSpell.DEFAULT_TRAITS, LightSpell::new); - public static final SpellType DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new); - public static final SpellType PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, PortalSpell.DEFAULT_TRAITS, PortalSpell::new); - public static final SpellType MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, SpellTraits.EMPTY, MimicSpell::new); - public static final SpellType MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, SpellTraits.EMPTY, MindSwapSpell::new); - public static final SpellType HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER)); - public static final SpellType BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new); - public static final SpellType DISPEL_EVIL = register("dispel_evil", Affinity.GOOD, 0x00FF00, true, DispellEvilSpell.DEFAULT_TRAITS, DispellEvilSpell::new); + public static final SpellType FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, GemstoneItem.Shape.TRIANGLE, IceSpell.DEFAULT_TRAITS, IceSpell::new); + public static final SpellType CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, GemstoneItem.Shape.TRIANGLE, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new); + public static final SpellType SCORCH = register("scorch", Affinity.BAD, 0xF8EC1F, true, GemstoneItem.Shape.FLAME, ScorchSpell.DEFAULT_TRAITS, ScorchSpell::new); + public static final SpellType FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, GemstoneItem.Shape.FLAME, FireSpell.DEFAULT_TRAITS, FireSpell::new); + public static final SpellType INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, GemstoneItem.Shape.FLAME, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new); + public static final SpellType SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, GemstoneItem.Shape.SHIELD, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new); + public static final SpellType ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, GemstoneItem.Shape.SHIELD, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new); + public static final SpellType VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, GemstoneItem.Shape.VORTEX, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new); + public static final SpellType DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, GemstoneItem.Shape.VORTEX, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new); + public static final SpellType NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, GemstoneItem.Shape.SKULL, SpellTraits.EMPTY, NecromancySpell::new); + public static final SpellType SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, GemstoneItem.Shape.LAMBDA, SpellTraits.EMPTY, SiphoningSpell::new); + public static final SpellType REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, GemstoneItem.Shape.CROSS, SpellTraits.EMPTY, DisperseIllusionSpell::new); + public static final SpellType AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, GemstoneItem.Shape.ICE, SpellTraits.EMPTY, AwkwardSpell::new); + public static final SpellType TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, GemstoneItem.Shape.BRUSH, SpellTraits.EMPTY, TransformationSpell::new); + public static final SpellType FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, GemstoneItem.Shape.LAMBDA, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new); + public static final SpellType CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, GemstoneItem.Shape.ROCKET, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new); + public static final SpellType FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, GemstoneItem.Shape.FLAME, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new); + public static final SpellType LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, GemstoneItem.Shape.STAR, LightSpell.DEFAULT_TRAITS, LightSpell::new); + public static final SpellType DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, GemstoneItem.Shape.BRUSH, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new); + public static final SpellType PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, GemstoneItem.Shape.RING, PortalSpell.DEFAULT_TRAITS, PortalSpell::new); + public static final SpellType MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, MimicSpell::new); + public static final SpellType MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, GemstoneItem.Shape.WAVE, SpellTraits.EMPTY, MindSwapSpell::new); + public static final SpellType HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER)); + public static final SpellType BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.DONUT, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new); + public static final SpellType DISPEL_EVIL = register("dispel_evil", Affinity.GOOD, 0x00FF00, true, GemstoneItem.Shape.CROSS, DispellEvilSpell.DEFAULT_TRAITS, DispellEvilSpell::new); public static void bootstrap() {} @@ -87,6 +82,7 @@ public final class SpellType implements Affine, SpellPredicate< private final Affinity affinity; private final int color; private final boolean obtainable; + private final GemstoneItem.Shape shape; private final Factory factory; @@ -98,11 +94,12 @@ public final class SpellType implements Affine, SpellPredicate< private final ItemStack defaultStack; - private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory factory) { + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { this.id = id; this.affinity = affinity; this.color = color; this.obtainable = obtainable; + this.shape = shape; this.factory = factory; this.traits = traits; traited = new CustomisedSpellType<>(this, traits); @@ -133,6 +130,10 @@ public final class SpellType implements Affine, SpellPredicate< return affinity; } + public GemstoneItem.Shape getGemShape() { + return shape; + } + public SpellTraits getTraits() { return traits; } @@ -178,15 +179,12 @@ public final class SpellType implements Affine, SpellPredicate< return "SpellType[" + getTranslationKey() + "]"; } - public static SpellType register(String name, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory factory) { - return register(Unicopia.id(name), affinity, color, obtainable, traits, factory); + public static SpellType register(String name, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { + return register(Unicopia.id(name), affinity, color, obtainable, shape, traits, factory); } - public static SpellType register(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory factory) { - SpellType type = new SpellType<>(id, affinity, color, obtainable, traits, factory); - byAffinity(affinity).add(type); - Registry.register(REGISTRY, id, type); - return type; + public static SpellType register(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory factory) { + return Registry.register(REGISTRY, id, new SpellType<>(id, affinity, color, obtainable, shape, traits, factory)); } @SuppressWarnings("unchecked") @@ -203,10 +201,6 @@ public final class SpellType implements Affine, SpellPredicate< return (SpellType)REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY); } - public static Set> byAffinity(Affinity affinity) { - return BY_AFFINITY.computeIfAbsent(affinity, a -> new LinkedHashSet<>()); - } - public static SpellType fromArgument(CommandContext context, String name) throws CommandSyntaxException { Identifier id = context.getArgument(name, RegistryKey.class).getValue(); return REGISTRY.getOrEmpty(id).orElseThrow(() -> UNKNOWN_SPELL_TYPE_EXCEPTION.create(id)); diff --git a/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java b/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java index d8c52062..23494849 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java +++ b/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java @@ -18,7 +18,9 @@ import com.minelittlepony.unicopia.entity.player.Pony; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.option.StickyKeyBinding; import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.client.util.InputUtil; import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; @@ -35,6 +37,10 @@ public class KeyBindingsHandler { private final Binding pageDown = register(GLFW.GLFW_KEY_PAGE_DOWN, "hud_page_dn"); private final Binding pageUp = register(GLFW.GLFW_KEY_PAGE_UP, "hud_page_up"); + private final Binding singleTapModifier = register(InputUtil.UNKNOWN_KEY.getCode(), "ability_modifier_tap"); + private final Binding doubleTapModifier = register(InputUtil.UNKNOWN_KEY.getCode(), "ability_modifier_double_tap"); + private final Binding tripleTapModifier = register(InputUtil.UNKNOWN_KEY.getCode(), "ability_modifier_triple_tap"); + private final Set pressed = new HashSet<>(); public KeyBindingsHandler() { @@ -47,8 +53,12 @@ public class KeyBindingsHandler { return reverse.get(slot); } + public boolean isToggleMode() { + return Unicopia.getConfig().toggleAbilityKeys.get(); + } + public void addKeybind(int code, AbilitySlot slot) { - Binding binding = register(code, slot.name().toLowerCase()); + Binding binding = new Binding(KeyBindingHelper.registerKeyBinding(new StickyKeyBinding("key.unicopia." + slot.name().toLowerCase(), code, KEY_CATEGORY, this::isToggleMode))); reverse.put(slot, binding); keys.put(binding, slot); } @@ -104,6 +114,7 @@ public class KeyBindingsHandler { int page = Unicopia.getConfig().hudPage.get(); page += sigma; Unicopia.getConfig().hudPage.set(page); + Unicopia.getConfig().save(); client.getSoundManager().play(PositionedSoundInstance.master(USounds.Vanilla.UI_BUTTON_CLICK, 1.75F + (0.25F * sigma))); UHud.INSTANCE.setMessage(Text.translatable("gui.unicopia.page_num", page + 1, max + 1)); } @@ -141,6 +152,27 @@ public class KeyBindingsHandler { } public ActivationType getType() { + if (binding.isPressed() && binding instanceof StickyKeyBinding) { + if (singleTapModifier.binding.isPressed()) { + KeyBinding.untoggleStickyKeys(); + return ActivationType.TAP; + } + + if (doubleTapModifier.binding.isPressed()) { + KeyBinding.untoggleStickyKeys(); + return ActivationType.DOUBLE_TAP; + } + + if (tripleTapModifier.binding.isPressed()) { + KeyBinding.untoggleStickyKeys(); + return ActivationType.TRIPLE_TAP; + } + + if (isToggleMode()) { + return ActivationType.NONE; + } + } + long now = System.currentTimeMillis(); if (type != ActivationType.NONE && now > nextPhaseTime - 70) { ActivationType t = type; diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 747465b5..704f90cb 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -122,7 +122,8 @@ public interface URenderers { register(URenderers::renderBedItem, UItems.CLOTH_BED, UItems.CLOUD_BED); register(URenderers::renderChestItem, UBlocks.CLOUD_CHEST.asItem()); PolearmRenderer.register(UItems.WOODEN_POLEARM, UItems.STONE_POLEARM, UItems.IRON_POLEARM, UItems.GOLDEN_POLEARM, UItems.DIAMOND_POLEARM, UItems.NETHERITE_POLEARM); - ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity, seed) -> EnchantableItem.isEnchanted(stack) ? EnchantableItem.getSpellKey(stack).getAffinity().getAlignment() : 0); + ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity, seed) -> EnchantableItem.getSpellKey(stack).getAffinity().getAlignment()); + ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("shape"), (stack, world, entity, seed) -> EnchantableItem.getSpellKey(stack).getGemShape().getId()); ModelPredicateProviderRegistry.register(UItems.ROCK_CANDY, new Identifier("count"), (stack, world, entity, seed) -> stack.getCount() / (float)stack.getMaxCount()); ModelPredicateProviderRegistry.register(UItems.BUTTERFLY, new Identifier("variant"), (stack, world, entity, seed) -> (float)ButterflyItem.getVariant(stack).ordinal() / ButterflyEntity.Variant.VALUES.length); ModelPredicateProviderRegistry.register(Unicopia.id("zap_cycle"), new ClampedModelPredicateProvider() { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java index ac454256..94b4ff54 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java @@ -68,6 +68,10 @@ public class SettingsScreen extends GameGui { }) .getStyle().setText("unicopia.options.ignore_mine_lp"); + content.addButton(new Toggle(LEFT, row += 20, config.toggleAbilityKeys.get())) + .onChange(config.toggleAbilityKeys) + .getStyle().setText("unicopia.options.toggle_ability_keys"); + mineLpStatus = content.addButton(new Label(LEFT, row += 10)).getStyle().setText(getMineLPStatus()); RegistryIndexer races = RegistryIndexer.of(Race.REGISTRY); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java index 4117c7e1..434f5dda 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.client.gui; +import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.client.KeyBindingsHandler; @@ -82,6 +83,12 @@ class Slot { bSwap &= abilities.isFilled(bSlot); } + AbilityDispatcher.Stat stat = abilities.getStat(bSwap ? bSlot : aSlot); + + if (stat.getAbility(Unicopia.getConfig().hudPage.get()).isEmpty()) { + return; + } + RenderSystem.setShaderColor(1, 1, 1, 1); RenderSystem.enableBlend(); MatrixStack matrices = context.getMatrices(); @@ -91,7 +98,7 @@ class Slot { // background context.drawTexture(UHud.HUD_TEXTURE, 0, 0, backgroundU, backgroundV, size, size, 128, 128); - AbilityDispatcher.Stat stat = abilities.getStat(bSwap ? bSlot : aSlot); + int iconPosition = ((size - iconSize + slotPadding + 1) / 2); int sz = iconSize - slotPadding; @@ -122,6 +129,11 @@ class Slot { } void renderLabel(DrawContext context, AbilityDispatcher abilities, float tickDelta) { + + if (abilities.getStat(aSlot).getAbility(Unicopia.getConfig().hudPage.get()).isEmpty()) { + return; + } + Text label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel(); MatrixStack matrices = context.getMatrices(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index ac25ce7d..59b89037 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -48,8 +48,8 @@ public class UHud { private final List slots = List.of( new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0), - new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 26, -5), - new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 36, 19) + new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -8), + new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 40, 18) ); @Nullable @@ -68,10 +68,6 @@ public class UHud { private SpellType focusedType = SpellType.empty(); public void render(InGameHud hud, DrawContext context, float tickDelta) { - - // TODO: Check this when backporting! - // InGameHud#renderHotbar line 460 - // context.getMatrices().translate(0.0f, 0.0f, -90.0f); final int hotbarZ = -90; if (client.player == null) { @@ -96,7 +92,6 @@ public class UHud { font = client.textRenderer; xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1; - matrices.push(); matrices.translate(scaledWidth / 2, scaledHeight / 2, 0); @@ -109,7 +104,7 @@ public class UHud { matrices.pop(); matrices.push(); - int hudX = ((scaledWidth - 50) / 2) + (104 * xDirection); + int hudX = ((scaledWidth - 50) / 2) + (109 * xDirection); int hudY = scaledHeight - 50; int hudZ = hotbarZ; @@ -139,33 +134,33 @@ public class UHud { slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); - boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace()) || Abilities.KIRIN_CAST.canUse(pony.getCompositeRace()); + + Ability ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) + .getAbility(Unicopia.getConfig().hudPage.get()) + .orElse(null); + boolean canCast = ability == Abilities.CAST || ability == Abilities.KIRIN_CAST || ability == Abilities.SHOOT; if (canCast) { - Ability ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) - .getAbility(Unicopia.getConfig().hudPage.get()) - .orElse(null); - - if (ability == Abilities.CAST || ability == Abilities.SHOOT) { - matrices.push(); - matrices.translate(PRIMARY_SLOT_SIZE / 2F, PRIMARY_SLOT_SIZE / 2F, 0); - boolean first = !pony.asEntity().isSneaking(); - TypedActionResult> inHand = pony.getCharms().getSpellInHand(false); - boolean replacing = inHand.getResult().isAccepted() && pony.getAbilities().getStat(AbilitySlot.PRIMARY).getActiveAbility().isEmpty(); - if (first != prevPointed || replacing != prevReplacing || inHand.getValue().type() != focusedType) { - focusedType = inHand.getValue().type(); - prevPointed = first; - prevReplacing = replacing; - setMessage(ability.getName(pony)); - } - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(first ? 37 : 63)); - matrices.translate(-23, 0, 0); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-26)); - matrices.scale(0.8F, 0.8F, 1); - int u = replacing ? 16 : 3; - context.drawTexture(HUD_TEXTURE, 0, 0, u, 120, 13, 7, 128, 128); - matrices.pop(); + matrices.push(); + matrices.translate(PRIMARY_SLOT_SIZE / 2F, PRIMARY_SLOT_SIZE / 2F, 0); + boolean first = !pony.asEntity().isSneaking(); + TypedActionResult> inHand = pony.getCharms().getSpellInHand(false); + boolean replacing = inHand.getResult().isAccepted() && pony.getAbilities().getStat(AbilitySlot.PRIMARY).getActiveAbility().isEmpty(); + if (first != prevPointed || replacing != prevReplacing || inHand.getValue().type() != focusedType) { + focusedType = inHand.getValue().type(); + prevPointed = first; + prevReplacing = replacing; + setMessage(ability.getName(pony)); } + int baseAngle = xDirection < 0 ? 100 : 0; + int secondAngleDif = xDirection * 30; + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(baseAngle + 37 + (first ? 0 : secondAngleDif))); + matrices.translate(-23, 0, 0); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-26)); + matrices.scale(0.8F, 0.8F, 1); + int u = replacing ? 16 : 3; + context.drawTexture(HUD_TEXTURE, 0, 0, u, 120, 13, 7, 128, 128); + matrices.pop(); } slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta)); @@ -173,8 +168,13 @@ public class UHud { matrices.pop(); if (canCast) { + matrices.push(); + if (xDirection < 0) { + hudX += PRIMARY_SLOT_SIZE / 2F - 8; + } SpellIconRenderer.renderSpell(context, pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 10 - xDirection * 13, hudY + 2, EQUIPPED_GEMSTONE_SCALE); SpellIconRenderer.renderSpell(context, pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 8 - xDirection * 2, hudY - 6, EQUIPPED_GEMSTONE_SCALE); + matrices.pop(); } RenderSystem.disableBlend(); @@ -198,7 +198,7 @@ public class UHud { float vortexDistortion = DarkVortexSpellRenderer.getCameraDistortion(); - if (vortexDistortion > 20) { + if (vortexDistortion > 25) { context.fill(RenderLayers.getEndPortal(), 0, 0, scaledWidth, scaledHeight, 0); context.getMatrices().push(); context.getMatrices().translate(scaledWidth / 2, scaledHeight / 2, 0); @@ -206,7 +206,7 @@ public class UHud { context.getMatrices().pop(); return; } else if (vortexDistortion > 0) { - context.fill(0, 0, scaledWidth, scaledHeight, (int)((vortexDistortion / 20F) * 255) << 24); + context.fill(0, 0, scaledWidth, scaledHeight, (int)((Math.min(20, vortexDistortion) / 20F) * 255) << 24); } boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS); diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java index 7b2f93e9..916f8ab2 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/BodyPartGear.java @@ -50,7 +50,7 @@ class BodyPartGear> implements Gear { public static final Predicate UNICORN_HORN_PREDICATE = MINE_LP_HAS_NO_HORN.and(AmuletSelectors.ALICORN_AMULET.or(EquinePredicates.raceMatches(com.minelittlepony.unicopia.Race::canCast))); public static final Identifier UNICORN_HORN = Unicopia.id("textures/models/horn/unicorn.png"); - public static final Predicate PEGA_WINGS_PREDICATE = MINE_LP_HAS_NO_WINGS.and(AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(race -> race.flightType() == FlightType.AVIAN))); + public static final Predicate PEGA_WINGS_PREDICATE = MINE_LP_HAS_NO_WINGS.and(AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(race -> race != com.minelittlepony.unicopia.Race.BAT && race.flightType() == FlightType.AVIAN))); public static final Identifier PEGASUS_WINGS = Unicopia.id("textures/models/wings/pegasus_pony.png"); public static BodyPartGear pegasusWings() { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/BatWingsFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/BatWingsFeatureRenderer.java index 32cb9aed..59af0f4f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/BatWingsFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/BatWingsFeatureRenderer.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.render; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.entity.AmuletSelectors; import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.client.model.Dilation; @@ -56,7 +57,9 @@ public class BatWingsFeatureRenderer extends WingsFeatur @Override protected boolean canRender(E entity) { - return entity instanceof PlayerEntity && Pony.of((PlayerEntity)entity).getObservedSpecies() == Race.BAT; + return entity instanceof PlayerEntity + && Pony.of((PlayerEntity)entity).getObservedSpecies() == Race.BAT + && !AmuletSelectors.PEGASUS_AMULET.test(entity); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java index 10c8ecc3..1a418971 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WingsFeatureRenderer.java @@ -1,7 +1,9 @@ package com.minelittlepony.unicopia.client.render; import com.minelittlepony.unicopia.FlightType; +import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.entity.AmuletSelectors; import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.client.model.Dilation; @@ -51,7 +53,10 @@ public class WingsFeatureRenderer implements AccessoryFe } protected boolean canRender(E entity) { - return entity instanceof PlayerEntity && Pony.of((PlayerEntity)entity).getObservedSpecies().flightType() == FlightType.AVIAN; + return entity instanceof PlayerEntity player + && Pony.of(player).getObservedSpecies().flightType() == FlightType.AVIAN + && Pony.of(player).getObservedSpecies() != Race.BAT + && !AmuletSelectors.PEGASUS_AMULET.test(entity); } protected Identifier getTexture(E entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java index aec3d2d8..f8a84c1a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java @@ -7,15 +7,17 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.DarkVortexSpell; import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.model.PlaneModel; import com.minelittlepony.unicopia.client.render.model.SphereModel; + import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.Camera; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; +import net.minecraft.util.math.Vec3d; public class DarkVortexSpellRenderer extends SpellRenderer { @@ -36,65 +38,72 @@ public class DarkVortexSpellRenderer extends SpellRenderer { @Override public void render(MatrixStack matrices, VertexConsumerProvider vertices, DarkVortexSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { - super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); + Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera(); - Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); + Vec3d ray = camera.getPos().subtract(spell.getOrigin(caster)); float radius = (float)spell.getEventHorizonRadius(); - float absDistance = (float)cameraEntity.getEyePos().distanceTo(caster.getOriginVector().add(0, 2, 0)); + + float absDistance = (float)ray.length(); matrices.push(); - matrices.translate(0, 2 + radius, 0); + matrices.translate(0, spell.getYOffset(), 0); + matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(-caster.asEntity().getYaw())); - SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getSolid()), light, 1, Math.min(radius * 0.6F, absDistance * 0.1F), 0, 0, 0, 1); + float visualRadius = Math.min(radius * 0.8F, absDistance - 1F); + + SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getSolid()), light, 1, visualRadius, 0, 0, 0, 1); + SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getMagicColored()), light, 1, visualRadius + 0.05F, 0, 0, 0, 0.9F); + SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getMagicColored()), light, 1, visualRadius + 0.1F, 0, 0, 0, 0.9F); + SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getMagicColored()), light, 1, visualRadius + 0.15F, 0, 0, 0, 0.9F); matrices.push(); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90)); - matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90 + cameraEntity.getYaw(tickDelta))); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); - matrices.scale(0.7F, 1, 1); - - float distance = 1F / MathHelper.clamp((absDistance / (radius * 4)), 0.0000001F, 1); + float distance = 1F / MathHelper.clamp(absDistance / (radius + 7), 0.0000001F, 1); distance *= distance; if (absDistance < radius * 4) { cameraDistortion += distance; } - matrices.scale(distance, distance, distance); - - if (absDistance > radius) { - matrices.push(); - matrices.translate(0, -0.1F, 0); - for (int i = 0; i < 10; i++) { - matrices.scale(1, 1, 0.796F); - float brightness = i / 10F; - SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getMagicNoColor()), light, 1, radius * (1 + (0.25F * i)) * 0.7F, brightness, brightness, brightness, 0.2F); - } - matrices.pop(); - } - - SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getEndPortal()), light, 1, radius * 0.5F, 1, 0.5F, 0, 1); + SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getEndPortal()), light, 1, radius * 0.5F, 0, 0, 0, 0); if (radius > 0.3F && absDistance > radius) { + double g = Math.sqrt(ray.x * ray.x + ray.z * ray.z); + float pitch = MathHelper.wrapDegrees((float)(-(MathHelper.atan2(ray.y, g) * 180.0F / (float)Math.PI))); + float yaw = MathHelper.wrapDegrees((float)(MathHelper.atan2(ray.z, ray.x) * 180.0F / (float)Math.PI) - 90.0F); + + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(caster.asEntity().getYaw())); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yaw)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-pitch)); + radius *= Math.min(2, 3 + radius); - matrices.scale(radius, radius, radius); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(animationProgress * 168)); + float processionSpeed = animationProgress * 0.02F; + float maxProcessionAngle = 15; + + float cosProcession = MathHelper.cos(processionSpeed); + float sinProcession = MathHelper.sin(processionSpeed); + + float range = (float)spell.getDrawDropOffRange() / 8F; + + matrices.scale(range, range, range); + + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(cosProcession * maxProcessionAngle)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(sinProcession * maxProcessionAngle)); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(animationProgress * 18)); + VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(ACCRETION_DISK_TEXTURE)); PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); - - matrices.push(); - matrices.scale(0.5F, 0.5F, 0.5F); + float secondaryScale = 0.9F + cosProcession * 0.3F; + matrices.translate(0, 0, 0.0001F); + matrices.scale(secondaryScale, secondaryScale, secondaryScale); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33)); - PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); - matrices.pop(); - - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(45)); + matrices.translate(0, 0, 0.0001F); + matrices.scale(0.9F, 0.9F, 0.9F); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33)); PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); } matrices.pop(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 72d0db23..c87430da 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -14,6 +14,9 @@ import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.entity.player.Pony; + import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer.TextLayerType; @@ -91,6 +94,9 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader if (client.getEntityRenderDispatcher().shouldRenderHitboxes() && !client.hasReducedDebugInfo() && !(caster.asEntity() == client.cameraEntity && client.options.getPerspective() == Perspective.FIRST_PERSON)) { + if (!(caster instanceof Pony || caster instanceof CastSpellEntity)) { + return; + } renderHotspot(matrices, vertices, caster, animationProgress); renderSpellDebugInfo(matrices, vertices, caster, light); } diff --git a/src/main/java/com/minelittlepony/unicopia/command/UCommandSuggestion.java b/src/main/java/com/minelittlepony/unicopia/command/UCommandSuggestion.java index 39d8f858..e8ab6b1c 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/UCommandSuggestion.java +++ b/src/main/java/com/minelittlepony/unicopia/command/UCommandSuggestion.java @@ -21,7 +21,7 @@ import net.minecraft.util.Identifier; public class UCommandSuggestion { public static final SuggestionProvider ALL_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY); - public static final SuggestionProvider ALLOWED_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY, (context, race) -> race.isPermitted(context.getSource().getPlayer())); + public static final SuggestionProvider ALLOWED_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY, (context, race) -> race.availability().isGrantable() && race.isPermitted(context.getSource().getPlayer())); public static SuggestionProvider suggestFromRegistry(RegistryKey> registryKey, @Nullable BiPredicate, T> filter) { return (context, builder) -> { @@ -43,7 +43,7 @@ public class UCommandSuggestion { } public static void forEachMatching(Iterable candidates, String input, Function idFunc, Consumer consumer, String defaultNamespace) { - final boolean hasNamespaceDelimiter = input.indexOf(58) > -1; + final boolean hasNamespaceDelimiter = input.indexOf(':') > -1; for (T object : candidates) { final Identifier id = idFunc.apply(object); if (hasNamespaceDelimiter) { diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/ModelOverrides.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/ModelOverrides.java index d5ff1b05..c0744cbe 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/ModelOverrides.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/ModelOverrides.java @@ -28,6 +28,13 @@ public final class ModelOverrides { this.model = model; } + public ModelOverrides addUniform(String key, Iterable values, Function idFunc, Function childModelSupplier) { + for (T t : values) { + addOverride(childModelSupplier.apply(t), key, idFunc.apply(t)); + } + return this; + } + public ModelOverrides addUniform(String key, int from, int to, Identifier model) { float step = 1F / to; for (int index = from; index <= to; index++) { diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java index cc317eb5..6861d8ed 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/UModelProvider.java @@ -1,12 +1,14 @@ package com.minelittlepony.unicopia.datagen.providers; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.datagen.DataCollector; import com.minelittlepony.unicopia.item.BedsheetsItem; +import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.UItems; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider; @@ -137,8 +139,7 @@ public class UModelProvider extends FabricModelProvider { // gemstone ModelOverrides.of(ItemModels.GENERATED) - .addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_pure"), "affinity", 0) - .addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_corrupted"), "affinity", 1) + .addUniform("shape", List.of(GemstoneItem.Shape.values()), GemstoneItem.Shape::getId, shape -> ModelIds.getItemSubModelId(UItems.GEMSTONE, "_" + shape.name().toLowerCase(Locale.ROOT))) .upload(UItems.GEMSTONE, itemModelGenerator); // fishing rod diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java index a576582d..12ddedd2 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java @@ -44,7 +44,11 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider { UBlocks.GOLDEN_OAK_SPROUT }; - getOrCreateTagBuilder(UTags.Blocks.CATAPULT_IMMUNE).add(Blocks.BEDROCK).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS); + getOrCreateTagBuilder(UTags.Blocks.CATAPULT_IMMUNE).add( + Blocks.STRUCTURE_VOID, Blocks.STRUCTURE_BLOCK, + Blocks.COMMAND_BLOCK, Blocks.CHAIN_COMMAND_BLOCK, Blocks.REPEATING_COMMAND_BLOCK, + Blocks.LIGHT, Blocks.JIGSAW, Blocks.BARRIER, Blocks.BEDROCK + ).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS); getOrCreateTagBuilder(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON).forceAddTag(BlockTags.ANIMALS_SPAWNABLE_ON).forceAddTag(BlockTags.LEAVES).forceAddTag(BlockTags.FLOWERS).forceAddTag(BlockTags.FLOWER_POTS); getOrCreateTagBuilder(UTags.Blocks.JARS).add(UBlocks.JAR, UBlocks.CLOUD_JAR, UBlocks.STORM_JAR, UBlocks.LIGHTNING_JAR, UBlocks.ZAP_JAR); getOrCreateTagBuilder(BlockTags.CROPS).add(crops); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java index ad6a4d4c..c401c1ce 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityReference.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; /** * An indirect reference to an entity by its unique id. - * Used to store the 'owner' reference for certain objects that allows them to\ + * Used to store the 'owner' reference for certain objects that allows them to * remember who they belong to even when the entity has been unloaded. * * Will also remember the position and certain attributes of the owner. diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java index 6a0731b4..ceaf6dad 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/ButterflyEntity.java @@ -11,7 +11,6 @@ import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.USounds; -import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.item.ButterflyItem; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -74,7 +73,7 @@ public class ButterflyEntity extends AmbientEntity { } public static boolean canSpawn(EntityType type, WorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) { - return world.getBlockState(pos.down()).isIn(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON); + return true;//world.getBlockState(pos.down()).isIn(UTags.Blocks.BUTTERFLIES_SPAWNABLE_ON); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java index 8d6ea782..76b0de8a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/UEntities.java @@ -26,7 +26,8 @@ import net.minecraft.world.Heightmap.Type; public interface UEntities { EntityType BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.AMBIENT).entityFactory(ButterflyEntity::new) - .spawnRestriction(Location.NO_RESTRICTIONS, Type.WORLD_SURFACE_WG, ButterflyEntity::canSpawn) + .spawnRestriction(Location.NO_RESTRICTIONS, Type.MOTION_BLOCKING_NO_LEAVES, ButterflyEntity::canSpawn) + .spawnableFarFromPlayer() .dimensions(EntityDimensions.fixed(0.25F, 0.25F))); EntityType THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.create(SpawnGroup.MISC, MagicProjectileEntity::new) .trackRangeBlocks(100) @@ -83,7 +84,7 @@ public interface UEntities { .trackRangeChunks(8) .dimensions(EntityDimensions.fixed(3, 2))); EntityType SPECTER = register("specter", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.MONSTER).entityFactory(SpecterEntity::new) - .spawnRestriction(Location.ON_GROUND, Type.WORLD_SURFACE, HostileEntity::canSpawnInDark) + .spawnRestriction(Location.ON_GROUND, Type.MOTION_BLOCKING_NO_LEAVES, HostileEntity::canSpawnIgnoreLightLevel) .fireImmune() .spawnableFarFromPlayer() .dimensions(EntityDimensions.fixed(1, 2))); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index fc53f9b0..1432887d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -1,7 +1,10 @@ package com.minelittlepony.unicopia.entity.player; +import java.util.Optional; import java.util.function.Supplier; +import org.jetbrains.annotations.Nullable; + import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; @@ -40,7 +43,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; -import net.minecraft.particle.BlockStateParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.registry.RegistryKeys; @@ -82,7 +84,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private int wallHitCooldown; - private Vec3d lastPos = Vec3d.ZERO; + @Nullable + private DimensionType lastDimension; + private Optional lastPos = Optional.empty(); private Vec3d lastVel = Vec3d.ZERO; private final PlayerDimensions dimensions; @@ -248,8 +252,14 @@ public class PlayerPhysics extends EntityPhysics implements Tickab ticksToGlide--; } - lastVel = entity.getPos().subtract(lastPos); - lastPos = entity.getPos(); + DimensionType dimension = entity.getWorld().getDimension(); + if (dimension != lastDimension) { + lastDimension = dimension; + lastPos = Optional.empty(); + } + + lastVel = lastPos.map(entity.getPos()::subtract).orElse(Vec3d.ZERO); + lastPos = Optional.of(entity.getPos()); final MutableVector velocity = new MutableVector(entity.getVelocity()); @@ -547,7 +557,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab private void checkAvianTakeoffConditions(MutableVector velocity) { double horMotion = getHorizontalMotion(); - double motion = entity.getPos().subtract(lastPos).lengthSquared(); + double motion = lastVel.lengthSquared(); boolean takeOffCondition = (horMotion > 0.05 || motion > 0.05) @@ -581,10 +591,10 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.calculateDimensions(); if (entity.isOnGround() || !force) { - BlockState steppingState = pony.asEntity().getSteppingBlockState(); - if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) { + //BlockState steppingState = pony.asEntity().getSteppingBlockState(); + /*if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) { pony.addParticle(new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), pony.getOrigin().toCenterPos(), Vec3d.ZERO); - } else { + } else*/ { Supplier pos = VecHelper.sphere(pony.asWorld().getRandom(), 0.5D); Supplier vel = VecHelper.sphere(pony.asWorld().getRandom(), 0.015D); pony.spawnParticles(ParticleTypes.CLOUD, pos, vel, 5); @@ -716,7 +726,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab } private void applyTurbulance(MutableVector velocity) { - int globalEffectStrength = MathHelper.clamp(entity.getWorld().getGameRules().getInt(UGameRules.WEATHER_EFFECTS_STRENGTH), 0, 100); + int globalEffectStrength = entity.getWorld().getGameRules().getInt(UGameRules.WEATHER_EFFECTS_STRENGTH); float effectStrength = Math.min(1, (float)ticksInAir / MAX_TICKS_TO_WEATHER_EFFECTS) * (globalEffectStrength / 100F); Vec3d gust = WeatherConditions.getGustStrength(entity.getWorld(), entity.getBlockPos()) .multiply(globalEffectStrength / 100D) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index fad4a95d..f973bc04 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -535,13 +535,15 @@ public class Pony extends Living implements Copyable, Update return; } - if (animationDuration > 0 && --animationDuration <= 0) { + if (animationDuration <= 0 || --animationDuration <= 0) { if (animation.renderBothArms() && acrobatics.distanceClimbed > 0) { return; } - setAnimation(AnimationInstance.NONE); + if (!getAnimation().isOf(Animation.NONE)) { + setAnimation(AnimationInstance.NONE); + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java b/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java index dba7218d..747115e1 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ConsumableItem.java @@ -4,8 +4,10 @@ import java.util.Optional; import net.minecraft.advancement.criterion.Criteria; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsage; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.stat.Stats; import net.minecraft.util.UseAction; @@ -29,7 +31,16 @@ public class ConsumableItem extends Item { serverPlayerEntity.incrementStat(Stats.USED.getOrCreateStat(this)); } - return stack.isEmpty() ? Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).orElse(ItemStack.EMPTY) : stack; + if (stack.isEmpty()) { + return stack.isEmpty() ? Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).orElse(ItemStack.EMPTY) : stack; + } + + if (user instanceof PlayerEntity player) { + return Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).map(remainder -> { + return ItemUsage.exchangeStack(stack, player, remainder); + }).orElse(stack); + } + return stack; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java index dcc35a05..8cb17b77 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java @@ -1,12 +1,10 @@ package com.minelittlepony.unicopia.item; -import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.function.Predicate; - import org.jetbrains.annotations.Nullable; -import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; @@ -96,12 +94,13 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem { @Override public List getDefaultStacks() { - return Arrays.stream(Affinity.VALUES) - .flatMap(i -> SpellType.byAffinity(i).stream() - .filter(type -> type.isObtainable()) - .map(type -> EnchantableItem.enchant(getDefaultStack(), type, i)) - ) - .toList(); + return SpellType.REGISTRY.stream() + .filter(SpellType::isObtainable) + .sorted( + Comparator., GemstoneItem.Shape>comparing(SpellType::getGemShape).thenComparing(Comparator.comparing(SpellType::getAffinity)) + ) + .map(type -> EnchantableItem.enchant(getDefaultStack(), type)) + .toList(); } @Override @@ -121,4 +120,29 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem { return super.getName(); } + public enum Shape { + ARROW, + BRUSH, + CROSS, + DONUT, + FLAME, + ICE, + LAMBDA, + RING, + ROCKET, + ROUND, + SHIELD, + SKULL, + SPLINT, + STAR, + TRIANGLE, + VORTEX, + WAVE; + + public static final int LENGTH = values().length; + + public float getId() { + return ordinal() / (float)LENGTH; + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 5e69e0d6..9ec070b3 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -111,7 +111,7 @@ public interface UItems { Item TOM = register("tom", new BluntWeaponItem(new Item.Settings(), ImmutableMultimap.of( EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, new EntityAttributeModifier(BluntWeaponItem.KNOCKBACK_MODIFIER_ID, "Weapon modifier", 0.9, EntityAttributeModifier.Operation.ADDITION) )), ItemGroups.NATURAL); - Item ROCK_STEW = register("rock_stew", new StewItem(new Item.Settings().food(FoodComponents.MUSHROOM_STEW).recipeRemainder(Items.BOWL)), ItemGroups.FOOD_AND_DRINK); + Item ROCK_STEW = register("rock_stew", new StewItem(new Item.Settings().food(FoodComponents.MUSHROOM_STEW).maxCount(1).recipeRemainder(Items.BOWL)), ItemGroups.FOOD_AND_DRINK); Item ROCK_CANDY = register("rock_candy", new Item(new Item.Settings().food(UFoodComponents.CANDY).maxCount(16)), ItemGroups.FOOD_AND_DRINK); Item SALT_CUBE = register("salt_cube", new Item(new Item.Settings().food(UFoodComponents.SALT_CUBE)), ItemGroups.FOOD_AND_DRINK); @@ -235,7 +235,7 @@ public interface UItems { Item COOKED_TROPICAL_FISH = register("cooked_tropical_fish", new Item(new Item.Settings().food(FoodComponents.COOKED_COD)), ItemGroups.FOOD_AND_DRINK); Item COOKED_PUFFERFISH = register("cooked_pufferfish", new Item(new Item.Settings().food(FoodComponents.COOKED_COD)), ItemGroups.FOOD_AND_DRINK); - Item FRIED_AXOLOTL = register("fried_axolotl", new ConsumableItem(new Item.Settings().food(FoodComponents.COOKED_CHICKEN).recipeRemainder(Items.BUCKET), UseAction.EAT), ItemGroups.FOOD_AND_DRINK); + Item FRIED_AXOLOTL = register("fried_axolotl", new ConsumableItem(new Item.Settings().food(FoodComponents.COOKED_CHICKEN).maxCount(1).recipeRemainder(Items.BUCKET), UseAction.EAT), ItemGroups.FOOD_AND_DRINK); Item GREEN_FRIED_EGG = register("green_fried_egg", new Item(new Item.Settings().food(UFoodComponents.FRIED_EGG)), ItemGroups.FOOD_AND_DRINK); Item CARAPACE = register("carapace", new Item(new Item.Settings()), ItemGroups.INGREDIENTS); diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 8d2e309c..d60b7607 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -211,7 +211,7 @@ public class Ether extends PersistentState { } public boolean isAvailable() { - return !isDead() && !taken; + return !isDead() && !taken && entity.isSet(); } public void setTaken(boolean taken) { @@ -219,6 +219,18 @@ public class Ether extends PersistentState { markDirty(); } + public void release() { + setTaken(false); + } + + public boolean claim() { + if (isAvailable()) { + setTaken(true); + return true; + } + return false; + } + @Nullable public T getSpell() { if (removed) { diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UGameRules.java b/src/main/java/com/minelittlepony/unicopia/server/world/UGameRules.java index 93fc32bd..cdf4f06a 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/UGameRules.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UGameRules.java @@ -1,15 +1,18 @@ package com.minelittlepony.unicopia.server.world; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; import net.minecraft.world.GameRules; import net.minecraft.world.GameRules.BooleanRule; import net.minecraft.world.GameRules.IntRule; public interface UGameRules { - GameRules.Key SWAP_TRIBE_ON_DEATH = GameRules.register("swapTribeOnDeath", GameRules.Category.SPAWNING, BooleanRule.create(false)); - GameRules.Key ANNOUNCE_TRIBE_JOINS = GameRules.register("announceTribeJoins", GameRules.Category.SPAWNING, BooleanRule.create(false)); - GameRules.Key DO_NOCTURNAL_BAT_PONIES = GameRules.register("doNocturnalBatPonies", GameRules.Category.PLAYER, BooleanRule.create(true)); - GameRules.Key WEATHER_EFFECTS_STRENGTH = GameRules.register("weatherEffectsStrength", GameRules.Category.MISC, IntRule.create(100)); - GameRules.Key DO_TIME_MAGIC = GameRules.register("doTimeMagic", GameRules.Category.PLAYER, BooleanRule.create(true)); + GameRules.Key SWAP_TRIBE_ON_DEATH = GameRuleRegistry.register("swapTribeOnDeath", GameRules.Category.SPAWNING, GameRuleFactory.createBooleanRule(false)); + GameRules.Key ANNOUNCE_TRIBE_JOINS = GameRuleRegistry.register("announceTribeJoins", GameRules.Category.SPAWNING, GameRuleFactory.createBooleanRule(false)); + GameRules.Key DO_NOCTURNAL_BAT_PONIES = GameRuleRegistry.register("doNocturnalBatPonies", GameRules.Category.PLAYER, GameRuleFactory.createBooleanRule(true)); + GameRules.Key WEATHER_EFFECTS_STRENGTH = GameRuleRegistry.register("weatherEffectsStrength", GameRules.Category.MISC, GameRuleFactory.createIntRule(100, 0, 100)); + GameRules.Key DO_TIME_MAGIC = GameRuleRegistry.register("doTimeMagic", GameRules.Category.PLAYER, GameRuleFactory.createBooleanRule(true)); + GameRules.Key MAX_DARK_VORTEX_SIZE = GameRuleRegistry.register("maxDarkVortexSize", GameRules.Category.PLAYER, GameRuleFactory.createIntRule(20, 1, 25)); static void bootstrap() { } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index df8a8f2e..523ff40e 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -544,7 +544,7 @@ "spell.unicopia.shield.lore": "Casts a protective shield around the user", "spell.unicopia.bubble": "Bubble", "spell.unicopia.bubble.lore": "Traps any creature it hits in a soap bubble", - "spell.unicopia.arcane_protection": "Arcane Protections", + "spell.unicopia.arcane_protection": "Arcane Protection", "spell.unicopia.arcane_protection.lore": "Creates a protective shroud over an area in which no other spells can be cast", "spell.unicopia.vortex": "Arcane Attraction", "spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets", @@ -1329,6 +1329,9 @@ "key.unicopia.secondary": "Secondary Ability", "key.unicopia.tertiary": "Tertiary Ability", "key.unicopia.passive": "Passive Ability", + "key.unicopia.ability_modifier_tap": "VR Ability Modifier (1-TAP)", + "key.unicopia.ability_modifier_double_tap": "VR Ability Modifier (2-TAP)", + "key.unicopia.ability_modifier_triple_tap": "VR Ability Modifier (3-TAP)", "key.unicopia.hud_page_dn": "Hud Previous Page", "key.unicopia.hud_page_up": "Hud Next Page", @@ -1408,6 +1411,7 @@ "commands.gravity.set.multiple": "Updated %s entities", "unicopia.options.title": "Unicopia Options", + "unicopia.options.toggle_ability_keys": "Sticky Ability Keys", "unicopia.options.ignore_mine_lp": "Ignore Mine Little Pony", "unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony is not installed", "unicopia.options.ignore_mine_lp.detected": "* Your detected race is %s", @@ -1427,28 +1431,28 @@ "command.unicopia.config.list": "[Config] Property (%s) contains (%s) entries: ", "command.unicopia.config.clear": "[Config] Cleared all values from property %s", - "unicopia.race.unset": "Unset", - "unicopia.race.unset.alt": "Unset", - "unicopia.race.human": "Human", - "unicopia.race.human.alt": "Humans", - "unicopia.race.earth": "Earth Pony", - "unicopia.race.earth.alt": "Earth Ponies", - "unicopia.race.unicorn": "Unicorn", - "unicopia.race.unicorn.alt": "Unicorns", - "unicopia.race.pegasus": "Pegasus", - "unicopia.race.pegasus.alt": "Pegasi", - "unicopia.race.alicorn": "Alicorn", - "unicopia.race.alicorn.alt": "Alicorns", - "unicopia.race.changeling": "Changeling", - "unicopia.race.changeling.alt": "Changelings", - "unicopia.race.bat": "Bat Pony", - "unicopia.race.bat.alt": "Bat Ponies", - "unicopia.race.kirin": "Kirin", - "unicopia.race.kirin.alt": "Kirins", - "unicopia.race.hippogriff": "Hippogriff", - "unicopia.race.hippogriff.alt": "Hippogriffs", - "unicopia.race.seapony": "Sea Pony", - "unicopia.race.seapony.alt": "Sea Ponies", + "race.unicopia.unset": "Unset", + "race.unicopia.unset.alt": "Unset", + "race.unicopia.human": "Human", + "race.unicopia.human.alt": "Humans", + "race.unicopia.earth": "Earth Pony", + "race.unicopia.earth.alt": "Earth Ponies", + "race.unicopia.unicorn": "Unicorn", + "race.unicopia.unicorn.alt": "Unicorns", + "race.unicopia.pegasus": "Pegasus", + "race.unicopia.pegasus.alt": "Pegasi", + "race.unicopia.alicorn": "Alicorn", + "race.unicopia.alicorn.alt": "Alicorns", + "race.unicopia.changeling": "Changeling", + "race.unicopia.changeling.alt": "Changelings", + "race.unicopia.bat": "Bat Pony", + "race.unicopia.bat.alt": "Bat Ponies", + "race.unicopia.kirin": "Kirin", + "race.unicopia.kirin.alt": "Kirins", + "race.unicopia.hippogriff": "Hippogriff", + "race.unicopia.hippogriff.alt": "Hippogriffs", + "race.unicopia.seapony": "Sea Pony", + "race.unicopia.seapony.alt": "Sea Ponies", "death.attack.unicopia.generic.and_also": "%1$s and %2$s", "death.attack.unicopia.generic.whilst_flying": "%1$s whilst flying", diff --git a/src/main/resources/assets/unicopia/lang/ru_ru.json b/src/main/resources/assets/unicopia/lang/ru_ru.json index 00fc3c1d..9030d03a 100644 --- a/src/main/resources/assets/unicopia/lang/ru_ru.json +++ b/src/main/resources/assets/unicopia/lang/ru_ru.json @@ -74,6 +74,14 @@ "item.unicopia.cooked_zap_apple": "Печёное зап-яблоко", "item.unicopia.zap_apple": "Зап-яблоко", "item.unicopia.zap_bulb": "Недозрелое зап-яблоко", + "item.unicopia.rotten_cod": "Гнилая треска", + "item.unicopia.rotten_salmon": "Гнилой лосось", + "item.unicopia.rotten_tropical_fish": "Гнилая тропическая рыба", + "item.unicopia.rotten_pufferfish": "Гнилой иглобрюх", + "item.unicopia.cooked_tropical_fish": "Приготовленная тропическая рыба", + "item.unicopia.cooked_pufferfish": "Приготовленный иглобрюх", + "item.unicopia.fried_axolotl": "Жареный аксолотль", + "item.unicopia.green_fried_egg": "Жареное зелёное яйцо", "item.unicopia.love_bottle": "Бутылочка любви", "item.unicopia.love_bucket": "Ведро любви", @@ -81,11 +89,16 @@ "item.unicopia.plunder_vine": "Чёрная лоза", "item.unicopia.empty_jar": "Стеклянная банка", + "block.unicopia.jar": "Стеклянная банка", "item.unicopia.filled_jar": "%s в банке", "item.unicopia.rain_cloud_jar": "Дождь в банке", + "item.unicopia.cloud_jar": "Дождь в банке", "item.unicopia.storm_cloud_jar": "Буря в банке", + "block.unicopia.storm_jar": "Буря в банке", "item.unicopia.lightning_jar": "Молния в банке", + "block.unicopia.lightning_jar": "Молния в банке", "item.unicopia.zap_apple_jam_jar": "Джем из зап-яблока", + "block.unicopia.zap_jar": "Банка зап-яблочного джема", "item.unicopia.toast": "Тост", "item.unicopia.burned_toast": "Подгоревший тост", @@ -145,7 +158,13 @@ "item.unicopia.crispy_hay_fries": "Хрустящий картофель фри", "item.unicopia.horse_shoe_fries": "Подкова из картофеля фри", "item.unicopia.wheat_worms": "Пшеничные черви", + "item.unicopia.baited_fishing_rod": "Удочка с приманкой", "item.unicopia.muffin": "Маффин", + "item.unicopia.scone": "Булочка", + "item.unicopia.oatmeal_cookie": "Овсяное печенье", + "item.unicopia.chocolate_oatmeal_cookie": "Шоколадное овсяное печенье", + "item.unicopia.pinecone_cookie": "Печенье из шишек", + "item.unicopia.bowl_of_nuts": "Миска с орехами", "item.unicopia.pegasus_amulet": "Крылья Икара", "item.unicopia.pegasus_amulet.lore": "Дарует временный полёт тому, кто носит его", @@ -197,6 +216,7 @@ "item.unicopia.music_disc_funk.desc": "Фанк, просто фанк", "item.unicopia.cloud_lump": "Облачный ком", + "item.unicopia.white_bed_sheets": "Белая простынь", "item.unicopia.light_gray_bed_sheets": "Светло-серая простынь", "item.unicopia.gray_bed_sheets": "Серая простынь", "item.unicopia.black_bed_sheets": "Черная простынь", @@ -279,6 +299,7 @@ "block.unicopia.golden_oak_leaves": "Листья золотого дуба", "block.unicopia.golden_oak_log": "Бревно золотого дуба", "block.unicopia.mango": "Манго", + "block.unicopia.worm_block": "Блок червей", "block.unicopia.mango_leaves": "Листья мангового дерева", "block.unicopia.mango_sapling": "Саженец мангового дерева", "block.unicopia.potted_mango_sapling": "Саженец манго в горшке", @@ -353,7 +374,8 @@ "block.unicopia.oats_crown": "Овёс", "entity.unicopia.butterfly": "Бабочка", - "entity.unicopia.twittermite": "Твиттермиты", + "entity.unicopia.twittermite": "Твиттермит", + "entity.unicopia.specter": "Призрак", "entity.unicopia.cast_spell": "Заклинание", "entity.unicopia.cast_spell.by": "Заклинание, наложенное %s", "entity.unicopia.spellbook": "Книга заклинаний", @@ -605,42 +627,43 @@ "unicopia.diet.hunger": "Коэффициент голода: %s%%", "unicopia.diet.saturation": "Коэффициент насыщения: %s%%", - "tag.unicopia.food_types.rotten_meat": "Гниющее мясо", - "tag.unicopia.food_types.raw_meat": "Свежее мясо", - "tag.unicopia.food_types.cooked_meat": "Готовое мясо", - "tag.unicopia.food_types.raw_fish": "Свежая рыба", - "tag.unicopia.food_types.cooked_fish": "Готовая рыба", - "tag.unicopia.food_types.raw_insect": "Жуки и насекомые", - "tag.unicopia.food_types.cooked_insect": "Приготовленные жуки и насекомые", - "tag.unicopia.food_types.nuts_and_seeds": "Орехи и семена", - "tag.unicopia.food_types.love": "Любовь", - "tag.unicopia.food_types.rocks": "Камни", - "tag.unicopia.food_types.pinecone": "Орехи и семена", - "tag.unicopia.food_types.bat_ponys_delight": "Лакомства бэтпони", - "tag.unicopia.food_types.cooked_sea_vegitables": "Готовая рыбная еда", - "tag.unicopia.food_types.raw_sea_vegitables": "Свежая рыбная еда", - "tag.unicopia.food_types.shells": "Морские ракушки", - "tag.unicopia.food_types.shelly": "Морские ракушки", - "tag.unicopia.food_types.candy": "Конфеты", - "tag.unicopia.food_types.desserts": "Десерты", - "tag.unicopia.food_types.fruit": "Фрукты", - "tag.unicopia.food_types.baked_goods": "Выпечка", - "tag.unicopia.food_types.misc": "Прочее", - "tag.unicopia.food_types.fruits_and_vegetables": "Фрукты и овощи", - "tag.unicopia.food_types.drinks": "Напитки", - "tag.minecraft.leaves": "Листья", - - "tag.unicopia.food_types.forage_edible_filling": "Крупная растительная масса", - "tag.unicopia.food_types.forage_edible": "Растительная масса", - "tag.unicopia.food_types.forage_nauseating": "Тошнотворное", - "tag.unicopia.food_types.forage_prickly": "Колючее", - "tag.unicopia.food_types.forage_risky": "Небезопасное", - "tag.unicopia.food_types.forage_strengthening": "Повышающее силу", - "tag.unicopia.food_types.forage_severely_prickly": "Очень колючее", - "tag.unicopia.food_types.forage_severely_nauseating": "Отвратительное", - "tag.unicopia.food_types.forage_radioactive": "Светящееся", - "tag.unicopia.food_types.forage_dangerous": "Опасное", - "tag.unicopia.food_types.forage_blinding": "Токсичное", + "food_group.unicopia.meat.rotten": "Гниющее мясо", + "food_group.unicopia.meat.raw": "Свежее мясо", + "food_group.unicopia.meat.cooked": "Готовое мясо", + "food_group.unicopia.fish.rotten": "Гнилая рыба", + "food_group.unicopia.fish.raw": "Свежая рыба", + "food_group.unicopia.fish.cooked": "Готовая рыба", + "food_group.unicopia.insect.rotten": "Гнилые жуки и насекомые", + "food_group.unicopia.insect.raw": "Жуки и насекомые", + "food_group.unicopia.insect.cooked": "Приготовленные жуки и насекомые", + "food_group.unicopia.nuts_and_seeds": "Орехи и семена", + "food_group.unicopia.love": "Любовь", + "food_group.unicopia.rocks": "Камни", + "food_group.unicopia.pinecone": "Орехи и семена", + "food_group.unicopia.bat_ponys_delight": "Лакомства бэтпони", + "food_group.unicopia.sea_vegetable.cooked": "Подготовленные ракушки и кораллы", + "food_group.unicopia.sea_vegetable.raw": "Ракушки и кораллы", + "food_group.unicopia.shells": "Морские ракушки", + "food_group.unicopia.special_shells": "Компаньоны", + "food_group.unicopia.candy": "Конфеты", + "food_group.unicopia.desserts": "Десерты", + "food_group.unicopia.fruit": "Фрукты", + "food_group.unicopia.baked_goods": "Выпечка", + "food_group.unicopia.misc": "Прочее", + "food_group.unicopia.fruits_and_vegetables": "Фрукты и овощи", + "food_group.unicopia.drinks": "Напитки", + "food_group.unicopia.foraging.edible_filling": "Крупная растительная масса", + "food_group.unicopia.foraging.edible": "Растительная масса", + "food_group.unicopia.foraging.nauseating": "Тошнотворное", + "food_group.unicopia.foraging.prickly": "Колючее", + "food_group.unicopia.foraging.risky": "Небезопасное", + "food_group.unicopia.foraging.strengthening": "Повышающее силу", + "food_group.unicopia.foraging.severely_prickly": "Очень колючее", + "food_group.unicopia.foraging.severely_nauseating": "Отвратительное", + "food_group.unicopia.foraging.radioactive": "Светящееся", + "food_group.unicopia.foraging.dangerous": "Опасное", + "food_group.unicopia.foraging.blinding": "Токсичное", + "food_group.unicopia.foraging.leafy_greens": "Листовая зелень", "toxicity.safe.name": "Безопасное", "toxicity.mild.name": "Слаботоксичное", @@ -1306,6 +1329,9 @@ "key.unicopia.secondary": "Вторичная способность", "key.unicopia.tertiary": "Третичная способность", "key.unicopia.passive": "Пассивная способность", + "key.unicopia.ability_modifier_tap": "Модификатор способностей VR (1-TAP)", + "key.unicopia.ability_modifier_double_tap": "Модификатор способностей VR (2-TAP)", + "key.unicopia.ability_modifier_triple_tap": "Модификатор способностей VR (3-TAP)", "key.unicopia.hud_page_dn": "Предыдущая страница", "key.unicopia.hud_page_up": "Следующая страница", @@ -1332,6 +1358,8 @@ "enchantment.unicopia.heart_bound.desc": "Заставляет предмет оставаться с вами после смерти", "enchantment.unicopia.consumption": "Потребление", "enchantment.unicopia.consumption.desc": "Преобразует предметы, добытые с помощью инструмента, в опыт", + "enchantment.unicopia.feather_touch": "Касание пера", + "enchantment.unicopia.feather_touch.desc": "Позволяет ломать и размещать облачные блоки при держании", "commands.race.success.self": "Изменена раса на %1$s.", "commands.race.success": "%1$s изменил расу на %2$s.", @@ -1380,8 +1408,10 @@ "commands.gravity.set": "Ваша гравитация была обновлена до %f", "commands.gravity.set.self": "Установить собственную гравитацию на %f", "commands.gravity.set.other": "Установить гравитацию %s на %f", + "commands.gravity.set.multiple": "Обновлено %s сущностей", "unicopia.options.title": "Опции Unicopia", + "unicopia.options.toggle_ability_keys": "Нажатие кнопки способности вместо зажатия", "unicopia.options.ignore_mine_lp": "Игнорировать Mine Little Pony", "unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony не установлен", "unicopia.options.ignore_mine_lp.detected": "* Ваша обнаруженная раса %s", @@ -1401,28 +1431,28 @@ "command.unicopia.config.list": "[Config] Свойство (%s) содержит (%s) записей:", "command.unicopia.config.clear": "[Config] Удалены все значения из свойства %s", - "unicopia.race.unset": "Не выбрано", - "unicopia.race.unset.alt": "не выбрано", - "unicopia.race.human": "Человек", - "unicopia.race.human.alt": "Люди", - "unicopia.race.earth": "Земной пони", - "unicopia.race.earth.alt": "Земные пони", - "unicopia.race.unicorn": "Единорог", - "unicopia.race.unicorn.alt": "Единороги", - "unicopia.race.pegasus": "Пегас", - "unicopia.race.pegasus.alt": "Пегасы", - "unicopia.race.alicorn": "Аликорн", - "unicopia.race.alicorn.alt": "Аликорны", - "unicopia.race.changeling": "Чейнджлинг", - "unicopia.race.changeling.alt": "Чейнджлинги", - "unicopia.race.bat": "Бэтпони", - "unicopia.race.bat.alt": "Бэтпони", - "unicopia.race.kirin": "Кирин", - "unicopia.race.kirin.alt": "Кирины", - "unicopia.race.hippogriff": "Гиппогриф", - "unicopia.race.hippogriff.alt": "Гиппогрифы", - "unicopia.race.seapony": "Морской пони", - "unicopia.race.seapony.alt": "Морские пони", + "race.unicopia.unset": "Не выбрано", + "race.unicopia.unset.alt": "не выбрано", + "race.unicopia.human": "Человек", + "race.unicopia.human.alt": "Люди", + "race.unicopia.earth": "Земной пони", + "race.unicopia.earth.alt": "Земные пони", + "race.unicopia.unicorn": "Единорог", + "race.unicopia.unicorn.alt": "Единороги", + "race.unicopia.pegasus": "Пегас", + "race.unicopia.pegasus.alt": "Пегасы", + "race.unicopia.alicorn": "Аликорн", + "race.unicopia.alicorn.alt": "Аликорны", + "race.unicopia.changeling": "Чейнджлинг", + "race.unicopia.changeling.alt": "Чейнджлинги", + "race.unicopia.bat": "Бэтпони", + "race.unicopia.bat.alt": "Бэтпони", + "race.unicopia.kirin": "Кирин", + "race.unicopia.kirin.alt": "Кирины", + "race.unicopia.hippogriff": "Гиппогриф", + "race.unicopia.hippogriff.alt": "Гиппогрифы", + "race.unicopia.seapony": "Морской пони", + "race.unicopia.seapony.alt": "Морские пони", "death.attack.unicopia.generic.and_also": "%1$s и %2$s", "death.attack.unicopia.generic.whilst_flying": "%1$s во время полёта", @@ -1592,13 +1622,23 @@ "advancements.unicopia.praise_the_sun.title": "Хвала Солнцу!", "advancements.unicopia.praise_the_sun.description": "Испытайте безудержную славу Селестии", "advancements.unicopia.cool_potato.title": "Крутая картошка", - "advancements.unicopia.cool_potato.description": "Защитите глаза от солнца", + "advancements.unicopia.cool_potato.description": "Защитите свои глаза от солнца", + "advancements.unicopia.take_a_note.title": "Записывай, Спайк", + "advancements.unicopia.take_a_note.description": "Получите свиток дыхания дракона", + "advancements.unicopia.dear_princess.title": "Дорогая принцесса...", + "advancements.unicopia.dear_princess.description": "Отправьте письмо с помощью свитка дыхания дракона", + "advancements.unicopia.i_await_your_reply.title": "Я жду твоего ответа", + "advancements.unicopia.i_await_your_reply.description": "Используйте свиток дыхания дракона, чтобы отправить кому-нибудь свиток дыхания дракона", "advancements.unicopia.baked_bads.title": "Запечённые хлебцы", "advancements.unicopia.baked_bads.description": "Испеките вкусный маффин", "advancements.unicopia.mid_flight_interruption.title": "Побеспокоили в середине полёта", "advancements.unicopia.mid_flight_interruption.description": "Получите удар молнии во время полёта в грозу", - "advancements.unicopia.lightning_bug.title": "Ошибка молнии", - "advancements.unicopia.lightning_bug.description": "Привлеките 10 ударов молний", + "advancements.unicopia.lightning_bug.title": "Баг молнии", + "advancements.unicopia.lightning_bug.description": "Привлеките 10 ударов молнии за чейнджлинга", + "advancements.unicopia.wonder_bolt.title": "Вондерболт", + "advancements.unicopia.wonder_bolt.description": "Привлеките 10 ударов молнии", + "advancements.unicopia.bait.title": "Это приманка?", + "advancements.unicopia.bait.description": "Насадите несколько червей на крючок", "advancements.unicopia.jar.title": "О, ничего себе. Что это?", "advancements.unicopia.jar.description": "Найдите пустую банку", "advancements.unicopia.gotcha.title": "Попался!", @@ -1606,11 +1646,17 @@ "advancements.unicopia.trick_apple.title": "Яблоко раздора", "advancements.unicopia.trick_apple.description": "Найдите своё первое зап-яблоко", "advancements.unicopia.feed_trick_apple.title": "Вот, попробуй это", - "advancements.unicopia.feed_trick_apple.description": "Скорми зап-яблоко мобу", + "advancements.unicopia.feed_trick_apple.description": "Скормите зап-яблоко мобу", "advancements.unicopia.eat_trick_apple.title": "Хрустящий", "advancements.unicopia.eat_trick_apple.description": "Кусните зап-яблоко", "advancements.unicopia.eat_pinecone.title": "Отчаяние", "advancements.unicopia.eat_pinecone.description": "Съешьте шишку", + "advancements.unicopia.tastes_like_chicken.title": "На вкус как курица", + "advancements.unicopia.tastes_like_chicken.description": "Зажарьте и съешьте аксолотля", + "advancements.unicopia.what_the_hay.title": "Какого сена?", + "advancements.unicopia.what_the_hay.description": "Съешьте целый блок сена", + "advancements.unicopia.oats_so_easy.title": "Овёс - это просто", + "advancements.unicopia.oats_so_easy.description": "Вырастите немного овса", "advancements.unicopia.imported_oats.title": "Столь же вкусные, сколь и дорогие", "advancements.unicopia.imported_oats.description": "Отправьте или получите шикарный импортный овёс", @@ -1640,11 +1686,15 @@ "advancements.unicopia.sweet_apple_acres.description": "Получите по одному яблоку каждого сорта", "advancements.unicopia.brew_cider.title": "Лучшее от Эпплджек", "advancements.unicopia.brew_cider.description": "Сварить сидр", + "advancements.unicopia.basket_case.title": "Дело о корзине", + "advancements.unicopia.basket_case.description": "Сплетите корзину", + "advancements.unicopia.aeronaut.title": "Аэронавт", + "advancements.unicopia.aeronaut.description": "Оснастите свою корзину фонарём и воздушным шаром", "advancements.unicopia.travelling_in_style.title": "Путешествие со стилем", "advancements.unicopia.travelling_in_style.description": "Прокатитесь на воздушном шаре", - "advancements.unicopia.night_route.title": "Дети Ночи", - "advancements.unicopia.night_route.description": "Пойдите по пути ночи", + "advancements.unicopia.bat_route.title": "Дети Ночи", + "advancements.unicopia.bat_route.description": "Пойдите по пути ночи", "advancements.unicopia.screech_twenty_mobs.title": "Ужас с неба", "advancements.unicopia.screech_twenty_mobs.description": "Обрушьте ужас по меньшей мере на 20 мобов одновременно", "advancements.unicopia.screech_self.title": "Божечки!", @@ -1657,10 +1707,18 @@ "advancements.unicopia.blasphemy.title": "Кощунство!", "advancements.unicopia.blasphemy.description": "Ударьте Селестию по башке. Упс!", - "advancements.unicopia.earth_route.title": "Путь Пони", + "advancements.unicopia.earth_route.title": "Очаг Земли", "advancements.unicopia.earth_route.description": "Вступить в клан Яблока", "advancements.unicopia.sticks_and_stones.title": "Палки и камни", "advancements.unicopia.sticks_and_stones.description": "Убейте моба, бросая в него камни", + "advancements.unicopia.blacksmith.title": "Кузнец", + "advancements.unicopia.blacksmith.description": "Сделайте подкову", + "advancements.unicopia.change_of_shoes.title": "Переобулся", + "advancements.unicopia.change_of_shoes.description": "Сделайте железную подкову", + "advancements.unicopia.fashionably_expensive.title": "Модно и дорого", + "advancements.unicopia.fashionably_expensive.description": "Обновитесь до золотых подков", + "advancements.unicopia.overkill.title": "Оверкилл", + "advancements.unicopia.overkill.description": "Создайте незеритовую подкову", "advancements.unicopia.dead_ringer.title": "Звон смерти", "advancements.unicopia.dead_ringer.description": "Убейте моба подковой", "advancements.unicopia.born_on_a_rock_farm.title": "Рождённый на Ферме Камней", @@ -1668,14 +1726,32 @@ "advancements.unicopia.thats_unusual.title": "Это необычно", "advancements.unicopia.thats_unusual.description": "Но что оно делает?", - "advancements.unicopia.sky_route.title": "Путь Пегаса", - "advancements.unicopia.sky_route.description": "Присоединяйтесь к пегасам Клаудсдейла", + "advancements.unicopia.pegasus_route.title": "Путь Пегаса", + "advancements.unicopia.pegasus_route.description": "Присоединитесь к пегасам Клаудсдейла", "advancements.unicopia.molting_season_1.title": "Сезон линьки", - "advancements.unicopia.molting_season_1.description": "Сбросьте перо во время полёта", + "advancements.unicopia.molting_season_1.description": "Сбросьте своё первое перо во время полёта", "advancements.unicopia.molting_season_2.title": "Сезон линьки 2", - "advancements.unicopia.molting_season_2.description": "Сбросьте 5 перьев во время полёта", + "advancements.unicopia.molting_season_2.description": "Сбросьте своё второе перо во время полёта", "advancements.unicopia.molting_season_3.title": "Сезон линьки 3", - "advancements.unicopia.molting_season_3.description": "Сбросьте 15 перьев во время полёта", + "advancements.unicopia.molting_season_3.description": "Сбросьте своё четвёртое перо во время полёта", + "advancements.unicopia.molting_season_4.title": "Сезон линьки 4", + "advancements.unicopia.molting_season_4.description": "Сбросьте своё восьмое перо во время полёта", + "advancements.unicopia.molting_season_5.title": "Сезон линьки 5", + "advancements.unicopia.molting_season_5.description": "Сбросьте своё шестнадцатое перо во время полёта", + "advancements.unicopia.molting_season_6.title": "Сезон линьки 6", + "advancements.unicopia.molting_season_6.description": "Сбросьте своё тридцать второе перо во время полёта", + "advancements.unicopia.molting_season_7.title": "Сезон линьки 7", + "advancements.unicopia.molting_season_7.description": "Сбросьте своё шестьдесят четвёртое перо во время полёта", + "advancements.unicopia.molting_season_8.title": "Сезон линьки 8", + "advancements.unicopia.molting_season_8.description": "Сбросьте своё сто двадцать восьмое перо во время полёта", + "advancements.unicopia.molting_season_9.title": "Сезон линьки 9", + "advancements.unicopia.molting_season_9.description": "Сбросьте своё двести пятьдесят шестое перо во время полёта", + "advancements.unicopia.molting_season_10.title": "Сезон линьки 10", + "advancements.unicopia.molting_season_10.description": "Сбросьте своё пятьсот двенадцатое перо во время полёта", + "advancements.unicopia.molting_season_11.title": "Сезон линьки 11", + "advancements.unicopia.molting_season_11.description": "Сбросьте своё тысяча двадцать четвёртое перо во время полёта", + "advancements.unicopia.dedicated_flier.title": "Всё в порядке, теперь ты можешь остановиться", + "advancements.unicopia.dedicated_flier.description": "Сбросьте своё две тысячи сорок восьмое перо во время полёта", "advancements.unicopia.rainbow_crash.title": "Дискорд тебя побери, Рэйнбоу", "advancements.unicopia.rainbow_crash.description": "Устройте войну против злой нации стеклянных окон", "advancements.unicopia.second_wind.title": "Второе дыхание", @@ -1683,11 +1759,13 @@ "advancements.unicopia.deter_phantom.title": "Что летает вокруг", "advancements.unicopia.deter_phantom.description": "Поднимитесь и дайте этим фантомам попробовать их собственное лекарство", - "advancements.unicopia.magical_route.title": "Рог единорога", - "advancements.unicopia.magical_route.description": "Окунитесь в мир блеска и радуги", + "advancements.unicopia.unicorn_route.title": "Рог единорога", + "advancements.unicopia.unicorn_route.description": "Окунитесь в мир блеска и радуги", "advancements.unicopia.books.title": "Книги!", "advancements.unicopia.books.description": "Это МОЯ книга заклинаний, и я собираюсь её ПРОЧИТАТЬ!", + "advancements.unicopia.books_books_books.title": "Книги! Книги! Книги!", + "advancements.unicopia.books_books_books.description": "Заполните инвентарь книгами", "advancements.unicopia.tempted.title": "Заманчиво...", "advancements.unicopia.tempted.description": "Наденьте амулет аликорна", "advancements.unicopia.hello_darkness_my_old_friend.title": "Здравствуй, Тьма...", @@ -1710,6 +1788,13 @@ "advancements.unicopia.love_is_power.title": "Любовь - это сила", "advancements.unicopia.love_is_power.description": "Изгоните короля Сомбра с помощью кристального сердца", + "advancements.unicopia.hippogriff_route.title": "Всплеск Сиквестрии", + "advancements.unicopia.hippogriff_route.description": "Присоединитесь к гнезду гиппогрифов", + "advancements.unicopia.shoo_be_doo.title": "Шу-би-ду!", + "advancements.unicopia.shoo_be_doo.description": "Используйте жемчужное ожерелье, чтобы превратиться в морское существо", + "advancements.unicopia.shoo_be_done.title": "Шу-би-всё!", + "advancements.unicopia.shoo_be_done.description": "Используйте жемчужное ожерелье, чтобы стать снова собой", + "unicopia.toast.discoveries.title": "Новые открытия!", "unicopia.toast.discoveries.description": "Проверьте свою книгу заклинаний" } diff --git a/src/main/resources/assets/unicopia/lang/zh_cn.json b/src/main/resources/assets/unicopia/lang/zh_cn.json index 9da5f8b3..d8a3fe99 100644 --- a/src/main/resources/assets/unicopia/lang/zh_cn.json +++ b/src/main/resources/assets/unicopia/lang/zh_cn.json @@ -197,6 +197,7 @@ "item.unicopia.music_disc_funk.desc": "funk, just funk", "item.unicopia.cloud_lump": "云团", + "item.unicopia.white_bed_sheets": "白色被单", "item.unicopia.light_gray_bed_sheets": "淡灰色被单", "item.unicopia.gray_bed_sheets": "灰色被单", "item.unicopia.black_bed_sheets": "黑色被单", @@ -228,7 +229,7 @@ "block.unicopia.spectral_fire": "节律火", "block.unicopia.bananas": "香蕉", "block.unicopia.zapling": "魔虹苹果树苗", - "block.unicopia.potted_zapling": "盆中 魔虹苹果树苗", + "block.unicopia.potted_zapling": "魔虹苹果树苗盆栽", "block.unicopia.zap_log": "魔虹苹果木原木", "block.unicopia.zap_wood": "魔虹苹果木", "block.unicopia.stripped_zap_log": "去皮魔虹苹果木原木", @@ -252,7 +253,7 @@ "block.unicopia.zap_apple": "魔虹苹果", "block.unicopia.zap_bulb": "没熟的魔虹苹果", "block.unicopia.palm_sapling": "棕榈树苗", - "block.unicopia.potted_palm_sapling": "盆中 棕榈树苗", + "block.unicopia.potted_palm_sapling": "棕榈树苗盆栽", "block.unicopia.palm_log": "棕榈木原木", "block.unicopia.palm_wood": "棕榈木", "block.unicopia.palm_planks": "棕榈木板", @@ -275,13 +276,13 @@ "block.unicopia.gold_root": "黄金根", "block.unicopia.golden_oak_sprout": "金橡树嫩芽", "block.unicopia.golden_oak_sapling": "金橡树树苗", - "block.unicopia.potted_golden_oak_sapling": "盆中 金橡树树苗", + "block.unicopia.potted_golden_oak_sapling": "金橡树树苗盆栽", "block.unicopia.golden_oak_leaves": "金橡树树叶", "block.unicopia.golden_oak_log": "金橡树原木", "block.unicopia.mango": "芒果", "block.unicopia.mango_leaves": "芒果树叶", "block.unicopia.mango_sapling": "芒果树苗", - "block.unicopia.potted_mango_sapling": "盆中 芒果树苗", + "block.unicopia.potted_mango_sapling": "芒果树苗盆栽", "block.unicopia.pineapple": "菠萝树", "block.unicopia.clam_shell": "蛤蜊壳", @@ -290,15 +291,15 @@ "block.unicopia.green_apple_leaves": "史密斯婆婆苹果树树叶", "block.unicopia.green_apple_sapling": "史密斯婆婆苹果树树苗", - "block.unicopia.potted_green_apple_sapling": "盆中 史密斯婆婆苹果树树苗", + "block.unicopia.potted_green_apple_sapling": "史密斯婆婆苹果树树苗盆栽", "block.unicopia.green_apple_sprout": "史密斯婆婆苹果嫩芽", "block.unicopia.sweet_apple_leaves": "甜苹果树树叶", "block.unicopia.sweet_apple_sapling": "甜苹果树树苗", - "block.unicopia.potted_sweet_apple_sapling": "盆中 甜苹果树树苗", + "block.unicopia.potted_sweet_apple_sapling": "甜苹果树树苗盆栽", "block.unicopia.sweet_apple_sprout": "甜苹果树嫩芽", "block.unicopia.sour_apple_leaves": "酸苹果树树叶", "block.unicopia.sour_apple_sapling": "酸苹果树树苗", - "block.unicopia.potted_sour_apple_sapling": "盆中 酸苹果树树苗", + "block.unicopia.potted_sour_apple_sapling": "酸苹果树树苗盆栽", "block.unicopia.sour_apple_sprout": "酸苹果树嫩芽", "block.unicopia.surface_chitin": "几丁质表面", @@ -612,6 +613,7 @@ "tag.unicopia.food_types.cooked_fish": "烤好的鱼", "tag.unicopia.food_types.raw_insect": "虫类", "tag.unicopia.food_types.cooked_insect": "烤虫类", + "tag.unicopia.food_types.nuts_and_seeds": "坚果和种子", "tag.unicopia.food_types.love": "爱", "tag.unicopia.food_types.rocks": "石块", "tag.unicopia.food_types.pinecone": "坚果和种子", @@ -1547,6 +1549,7 @@ "unicopia.subtitle.pegasus.molt": "天马:脱羽", "unicopia.subtitle.unicorn.teleport": "魔法:啵", "unicopia.subtitle.player.wololo": "Wololo!", + "unicopia.subtitle.corrupt": "魔法:堕落", "unicopia.subtitle.entity.player.whistle": "玩家吹口哨", "unicopia.subtitle.entity.player.kick": "玩家:踢腿", "unicopia.subtitle.magic_aura": "魔法:嗡嗡", @@ -1591,12 +1594,18 @@ "advancements.unicopia.praise_the_sun.description": "感受太阳公主的无上熔光", "advancements.unicopia.cool_potato.title": "酷毙了", "advancements.unicopia.cool_potato.description": "保护你的眼睛不受阳光侵袭", + "advancements.unicopia.take_a_note.title": "穗龙,把这个记下来", + "advancements.unicopia.take_a_note.description": "获得龙息卷轴", + "advancements.unicopia.dear_princess.title": "亲爱的公主殿下……", + "advancements.unicopia.dear_princess.description": "用龙息卷轴送出一份信", "advancements.unicopia.baked_bads.title": "烤砸了", - "advancements.unicopia.baked_bads.description": "烤制美味马芬", + "advancements.unicopia.baked_bads.description": "烤制美味玛芬", "advancements.unicopia.mid_flight_interruption.title": "风雷混合双打", "advancements.unicopia.mid_flight_interruption.description": "在风暴中飞行时被雷劈到", "advancements.unicopia.lightning_bug.title": "引火虫", - "advancements.unicopia.lightning_bug.description": "引得十次雷劈", + "advancements.unicopia.lightning_bug.description": "作为幻形灵,引得十次雷劈", + "advancements.unicopia.wonder_bolt.title": "闪电天马", + "advancements.unicopia.wonder_bolt.description": "引得十次雷劈", "advancements.unicopia.jar.title": "哇哦,这是什么?", "advancements.unicopia.jar.description": "找到一个空罐子", "advancements.unicopia.gotcha.title": "抓到你了!", @@ -1669,15 +1678,33 @@ "advancements.unicopia.sky_route.title": "飞彳亍", "advancements.unicopia.sky_route.description": "入驻云中城", "advancements.unicopia.molting_season_1.title": "换羽季节I", - "advancements.unicopia.molting_season_1.description": "飞行时掉下一根羽毛", + "advancements.unicopia.molting_season_1.description": "飞行时掉下第1根羽毛", "advancements.unicopia.molting_season_2.title": "换羽季节II", - "advancements.unicopia.molting_season_2.description": "飞行时掉下五根羽毛", + "advancements.unicopia.molting_season_2.description": "飞行时掉下第2根根羽毛", "advancements.unicopia.molting_season_3.title": "换羽季节III", - "advancements.unicopia.molting_season_3.description": "飞行时掉下十五根羽毛", + "advancements.unicopia.molting_season_3.description": "飞行时掉下第4根羽毛", + "advancements.unicopia.molting_season_4.title": "换羽季节IV", + "advancements.unicopia.molting_season_4.description": "飞行时掉下第8根羽毛", + "advancements.unicopia.molting_season_5.title": "换羽季节V", + "advancements.unicopia.molting_season_5.description": "飞行时掉下第16根羽毛", + "advancements.unicopia.molting_season_6.title": "换羽季节VI", + "advancements.unicopia.molting_season_6.description": "飞行时掉下第32根羽毛", + "advancements.unicopia.molting_season_7.title": "换羽季节VII", + "advancements.unicopia.molting_season_7.description": "飞行时掉下第64根羽毛", + "advancements.unicopia.molting_season_8.title": "换羽季节VIII", + "advancements.unicopia.molting_season_8.description": "飞行时掉下第128根羽毛", + "advancements.unicopia.molting_season_9.title": "换羽季节IX", + "advancements.unicopia.molting_season_9.description": "飞行时掉下第256根羽毛", + "advancements.unicopia.molting_season_10.title": "换羽季节X", + "advancements.unicopia.molting_season_10.description": "飞行时掉下第512根羽毛", + "advancements.unicopia.molting_season_11.title": "换羽季节XI", + "advancements.unicopia.molting_season_11.description": "飞行时掉下第1024根羽毛", + "advancements.unicopia.dedicated_flier.title": "谢谢,够了", + "advancements.unicopia.dedicated_flier.description": "飞行时掉下第2048根羽毛", "advancements.unicopia.rainbow_crash.title": "去你的彩虹", "advancements.unicopia.rainbow_crash.description": "向邪恶的玻璃国宣战", "advancements.unicopia.second_wind.title": "来劲了", - "advancements.unicopia.second_wind.description": "竭力飞行", + "advancements.unicopia.second_wind.description": "难受啊马飞", "advancements.unicopia.deter_phantom.title": "神仙斗法", "advancements.unicopia.deter_phantom.description": "马飞飞,让那些修仙的幻翼永远安眠吧", diff --git a/src/main/resources/assets/unicopia/lang/zh_tw.json b/src/main/resources/assets/unicopia/lang/zh_tw.json index 211b7ffa..db364961 100644 --- a/src/main/resources/assets/unicopia/lang/zh_tw.json +++ b/src/main/resources/assets/unicopia/lang/zh_tw.json @@ -6,13 +6,13 @@ "sleep.not_possible.nocturnal": "您無法跳過這一天", "sleep.skipping_day": "這一天將在睡夢中度過", - "ability.unicopia.empty_hooves": "我需要找到一個罐子", + "ability.unicopia.empty_hooves": "我需要一個罐子", "ability.unicopia.indoors": "我在這裏看不到天空", - "ability.unicopia.too_low": "我需要飛得更高", - "ability.unicopia.clear_skies": "天空看起來已經很晴朗了", - "ability.unicopia.too_calm.1": "我需要更加憤怒……", - "ability.unicopia.too_calm.2": "我並不感到憤怒……", - "ability.unicopia.too_calm.3": "李小龍讓這看着好輕鬆啊……", + "ability.unicopia.too_low": "我要飛得更高", + "ability.unicopia.clear_skies": "天空已經很晴朗了", + "ability.unicopia.too_calm.1": "我的怒火要更加旺盛一些……", + "ability.unicopia.too_calm.2": "我並不怎麼生氣……", + "ability.unicopia.too_calm.3": "李小龍這麼做看着好輕鬆啊……", "ability.unicopia.too_calm.4": "塞蕾斯蒂亞公主,請賜予我力量……", "itemGroup.unicopia.items": "Unicopia", @@ -25,7 +25,7 @@ "itemGroup.unicopia.changeling": "Unicopia - 幻形峭壁", "item.unicopia.friendship_bracelet": "友誼手鐲", - "item.unicopia.friendship_bracelet.issuer": "由 %s 簽名", + "item.unicopia.friendship_bracelet.issuer": "由%s簽名", "item.unicopia.friendship_bracelet.glowing": "正在發光", "item.unicopia.oak_basket": "橡木籃", @@ -49,6 +49,9 @@ "emi.category.unicopia.spellbook": "咒語書", "emi.category.unicopia.cloud_shaping": "塑形", "emi.category.unicopia.growing": "生長", + "emi.category.unicopia.altar": "黑暗儀式", + "recipe.unicopia.altar.instruction": "火焰侵蝕物品", + "recipe.unicopia.growing.instruction": "聚焦陸馬魔法", "item.unicopia.alicorn_badge": "天角徽章", "item.unicopia.unicorn_badge": "獨角徽章", @@ -79,9 +82,9 @@ "item.unicopia.plunder_vine": "掠奪藤蔓", "item.unicopia.empty_jar": "玻璃罐", "item.unicopia.filled_jar": "%s罐", - "item.unicopia.rain_cloud_jar": "雨罐", + "item.unicopia.rain_cloud_jar": "雨雲罐", "item.unicopia.storm_cloud_jar": "暴雨罐", - "item.unicopia.lightning_jar": "雷電罐", + "item.unicopia.lightning_jar": "閃電罐", "item.unicopia.zap_apple_jam_jar": "彩虹蘋果醬罐", "item.unicopia.toast": "烤麪包片", @@ -156,7 +159,7 @@ "item.unicopia.clam_shell": "蛤殼", "item.unicopia.scallop_shell": "貝殼", "item.unicopia.turret_shell": "塔殼", - "item.unicopia.shelly": "小殼", + "item.unicopia.shelly": "螺螺", "item.unicopia.horse_shoe.accuracy": "精準度:%d%%", "item.unicopia.horse_shoe.speed": "速度:%d", @@ -194,6 +197,7 @@ "item.unicopia.music_disc_funk.desc": "Death by Glamour", "item.unicopia.cloud_lump": "雲塊", + "item.unicopia.white_bed_sheets": "白色被單", "item.unicopia.light_gray_bed_sheets": "淡灰被單", "item.unicopia.gray_bed_sheets": "灰色被單", "item.unicopia.black_bed_sheets": "黑色被單", @@ -222,17 +226,34 @@ "block.unicopia.rocks": "岩石", "block.unicopia.plunder_vine": "掠奪藤蔓", "block.unicopia.plunder_vine_bud": "掠奪藤蔓芽", + "block.unicopia.spectral_fire": "光譜火焰", "block.unicopia.bananas": "香蕉", "block.unicopia.zapling": "彩虹蘋果苗", + "block.unicopia.potted_zapling": "彩虹蘋果苗盆栽", "block.unicopia.zap_log": "彩虹蘋果原木", "block.unicopia.zap_wood": "彩虹蘋果木塊", "block.unicopia.stripped_zap_log": "剝皮彩虹蘋果原木", "block.unicopia.stripped_zap_wood": "剝皮彩虹蘋果木塊", + "block.unicopia.zap_planks": "彩虹蘋果木木材", + "block.unicopia.zap_stairs": "彩虹蘋果木階梯", + "block.unicopia.zap_slab": "彩虹蘋果木半磚", + "block.unicopia.zap_fence": "彩虹蘋果木柵欄", + "block.unicopia.zap_fence_gate": "彩虹蘋果木柵欄門", + "block.unicopia.waxed_zap_log": "上蠟彩虹蘋果原木", + "block.unicopia.waxed_zap_wood": "上蠟彩虹蘋果木塊", + "block.unicopia.waxed_stripped_zap_log": "去皮上蠟彩虹蘋果原木", + "block.unicopia.waxed_stripped_zap_wood": "去皮上蠟彩虹蘋果木塊", + "block.unicopia.waxed_zap_planks": "上蠟彩虹蘋果木木材", + "block.unicopia.waxed_zap_stairs": "上蠟彩虹蘋果木階梯", + "block.unicopia.waxed_zap_slab": "上蠟彩虹蘋果木半磚", + "block.unicopia.waxed_zap_fence": "上蠟彩虹蘋果木柵欄", + "block.unicopia.waxed_zap_fence_gate": "上蠟彩虹蘋果木柵欄門", "block.unicopia.zap_leaves": "彩虹蘋果樹葉", "block.unicopia.flowering_zap_leaves": "開花彩虹蘋果樹葉", "block.unicopia.zap_apple": "彩虹蘋果", "block.unicopia.zap_bulb": "生彩虹蘋果", "block.unicopia.palm_sapling": "棕櫚苗", + "block.unicopia.potted_palm_sapling": "棕櫚苗盆栽", "block.unicopia.palm_log": "棕櫚原木", "block.unicopia.palm_wood": "棕櫚木塊", "block.unicopia.palm_planks": "棕櫚木材", @@ -255,11 +276,13 @@ "block.unicopia.gold_root": "金橡樹根", "block.unicopia.golden_oak_sprout": "金橡樹芽", "block.unicopia.golden_oak_sapling": "金橡樹苗", + "block.unicopia.potted_golden_oak_sapling": "金橡樹苗盆栽", "block.unicopia.golden_oak_leaves": "金橡樹葉", "block.unicopia.golden_oak_log": "金橡樹原木", "block.unicopia.mango": "芒果", "block.unicopia.mango_leaves": "芒果葉", - "block.unicopia.mango_sapling": "芒果葉", + "block.unicopia.mango_sapling": "芒果苗", + "block.unicopia.potted_mango_sapling": "芒果苗盆栽", "block.unicopia.pineapple": "鳳梨株", "block.unicopia.clam_shell": "蛤殼", @@ -268,12 +291,15 @@ "block.unicopia.green_apple_leaves": "婆婆蘋果樹葉", "block.unicopia.green_apple_sapling": "婆婆蘋果苗", + "block.unicopia.potted_green_apple_sapling": "婆婆蘋果苗盆栽", "block.unicopia.green_apple_sprout": "婆婆蘋果芽", "block.unicopia.sweet_apple_leaves": "香甜蘋果樹葉", "block.unicopia.sweet_apple_sapling": "香甜蘋果苗", + "block.unicopia.potted_sweet_apple_sapling": "香甜蘋果苗盆栽", "block.unicopia.sweet_apple_sprout": "香甜蘋果芽", "block.unicopia.sour_apple_leaves": "酸蘋果樹葉", "block.unicopia.sour_apple_sapling": "酸蘋果苗", + "block.unicopia.potted_sour_apple_sapling": "酸蘋果苗盆栽", "block.unicopia.sour_apple_sprout": "酸蘋果芽", "block.unicopia.surface_chitin": "表殼", @@ -575,8 +601,8 @@ "unicopia.diet.side_effects": "副作用:", "unicopia.diet.not_edible": "物品不可食用", "unicopia.diet.base_multiplier": "基礎倍增:%s%%", - "unicopia.diet.hunger.detailed": "獲得飢餓:%s of %s (%s%%)", - "unicopia.diet.saturation.detailed": "獲得飽食: %s (%s%%)", + "unicopia.diet.hunger.detailed": "獲得飢餓:%s分之%s (%s%%)", + "unicopia.diet.saturation.detailed": "獲得飽食: %s分之%s (%s%%)", "unicopia.diet.hunger": "飢餓比:%s%%", "unicopia.diet.saturation": "飽食比:%s%%", @@ -587,6 +613,7 @@ "tag.unicopia.food_types.cooked_fish": "熟魚", "tag.unicopia.food_types.raw_insect": "蟲", "tag.unicopia.food_types.cooked_insect": "熟蟲", + "tag.unicopia.food_types.nuts_and_seeds": "堅果與種子", "tag.unicopia.food_types.love": "愛意", "tag.unicopia.food_types.rocks": "岩石", "tag.unicopia.food_types.pinecone": "堅果與種子", @@ -594,11 +621,15 @@ "tag.unicopia.food_types.cooked_sea_vegitables": "熟魚食", "tag.unicopia.food_types.raw_sea_vegitables": "鮮魚食", "tag.unicopia.food_types.shells": "海螺", - "tag.unicopia.food_types.shelly": "海螺", + "tag.unicopia.food_types.shelly": "螺螺", "tag.unicopia.food_types.candy": "糖果", "tag.unicopia.food_types.desserts": "點心", + "tag.unicopia.food_types.fruit": "水果", + "tag.unicopia.food_types.baked_goods": "烘培", + "tag.unicopia.food_types.misc": "雜項", "tag.unicopia.food_types.fruits_and_vegetables": "水果與蔬菜", "tag.unicopia.food_types.drinks": "飲料", + "tag.minecraft.leaves": "葉類", "tag.unicopia.food_types.forage_edible_filling": "大型植質", "tag.unicopia.food_types.forage_edible": "植質", @@ -773,14 +804,14 @@ "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.bat": " - Is sometimes scared of even themselves", "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.bat": " - Is carnivorous. Can eat raw and cooked meat, or sustain themselved purely on stolen love.", - "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.changeling": " - Are always starving", - "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.changeling": " - Requires love, collected from ponies or other hostile mobs to subsidise their diet", - "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.changeling": " - Becomes sick from eating most regular food and must harvest love to hasten a cure", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.changeling": " - 一直餓肚子", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.changeling": " - 需要從其他小馬或敵對生物吸取愛意來填飽肚子", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.changeling": " - 吃絕大多數普通食物會生病,必須收穫愛意來治癒", - "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.kirin": " - Are no longer quiet whilst raging", - "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.kirin": " - Has a tendency to burn things, especially when close to raging", - "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.kirin": " - Lighter than other ponies, and might take increased knockback", - "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.kirin": " - Doesn't like water", + "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.kirin": " - 發火時不再安靜", + "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.kirin": " - 傾向于燒東西,尤其是在發火時", + "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.kirin": " - 比其他小馬輕盈,可能更容易被擊退", + "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.kirin": " - 不喜歡水", "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.hippogriff": " - 易受蠻力攻擊", "gui.unicopia.tribe_selection.confirm.bads.2.unicopia.hippogriff": " - 無法和雲交互", @@ -911,8 +942,6 @@ "gui.unicopia.spellbook.chapter.ice.p7.title": "Bonfire II", "gui.unicopia.spellbook.chapter.ice.p7.1.body": "On the way back Luna was telling me of the stories her friend told her. The town has a lot of legends, as to be expected.", "gui.unicopia.spellbook.chapter.ice.p7.2.body": "One of them was about a scary old warlock who lived in a haunted tower at the edge of town. There's no mystery who that was about.", - "gui.unicopia.spellbook.chapter.ice.p7.3.body": "Ice Spell II", - "gui.unicopia.spellbook.chapter.ice.p7.4.body": "Creates a cooling affect up to a radius of 3 hooves from any surfaces it touches.", "gui.unicopia.spellbook.chapter.ice.p8.title": "6th Trot '12", "gui.unicopia.spellbook.chapter.ice.p8.1.body": "There was a strange noise in the village last night. Very strange. I heard a lot ponies shouting and there may have been a fire.", "gui.unicopia.spellbook.chapter.ice.p8.2.body": "I hope everything is okay.", @@ -1118,6 +1147,10 @@ "gui.unicopia.spellbook.chapter.artefacts.torn_page.2.body": "§kAasa sasa fwefsd q43rgfd wqklmsdfl as, klasn.§r", "gui.unicopia.spellbook.chapter.artefacts.torn_page.3.body": "Building Materials:", "gui.unicopia.spellbook.chapter.artefacts.crystal_podium.title": "Crystal Podium", + "gui.unicopia.spellbook.chapter.artefacts.altar.title": "Altar", + "gui.unicopia.spellbook.chapter.artefacts.altar.1.body": "An an§kc§rient altar con§ktr§ructed by an early t§kr§ribe of §kunicorn§rs. It's thought that these were used to perform r§kituals§r sum§kmoni§rng upon §keven o§rlder mag§kics§r.", + "gui.unicopia.spellbook.chapter.artefacts.altar.2.body": "Not much is §kkn§rown about these my§ks§rterious structures, and they hold many secrets even to this day.", + "gui.unicopia.spellbook.chapter.artefacts.altar.3.body": "U§ks§re the §ka§rltar", "gui.unicopia.spellbook.chapter.artefacts.dragon_breath_scroll.2.body": "It's, um a scroll that you write somepony's name on it and you hold it in one hoof and something in the other hoof and, like, um it goes whooosh and the item is sent to that pony.", "gui.unicopia.spellbook.chapter.artefacts.dragon_breath_scroll.title": "2nd Hoof '12", "gui.unicopia.spellbook.chapter.artefacts.dragon_breath_scroll.3.body": "P.S. Uncle Starswirly is a dunderhead.", @@ -1126,6 +1159,9 @@ "gui.unicopia.spellbook.chapter.artefacts.friendship_bracelet.title": "13th Mare '12", "gui.unicopia.spellbook.chapter.artefacts.friendship_bracelet.3.body": "Anyone wearing a bangle you have signed will be able to benefit from the positive effects of your spells, or will be allowed through protection and shield spells.", "gui.unicopia.spellbook.chapter.artefacts.friendship_bracelet.4.body": "Mana costs are also shared equally between all nearby members.", + "gui.unicopia.spellbook.chapter.artefacts.spectral_clock.title": "14th Mare '12", + "gui.unicopia.spellbook.chapter.artefacts.spectral_clock.1.body": "Not so much an artefact as a strange trinket. Luna happened to bring this home from the market last week, and though at first glance it may seem to be an ordinary broken clock what I've found is far stranger.", + "gui.unicopia.spellbook.chapter.artefacts.spectral_clock.2.body": "This clock doesn't tell the time. Well, it does, but not directly. Rather it seems to be following the cycles of some of the plants in the surrounding forest.", "gui.unicopia.spellbook.chapter.artefacts.pegasus_amulet.1.body": "Commander Hurricane informed me of this, though I've found little texts to back up his claims.", "gui.unicopia.spellbook.chapter.artefacts.pegasus_amulet.2.body": "The Pegasus Amulet is claimed to grant the wearer temporary flight, like a pegasus.", "gui.unicopia.spellbook.chapter.artefacts.pegasus_amulet.title": "21st Trot '12", @@ -1155,16 +1191,16 @@ "gui.unicopia.action.spells_cleared": "已移除所有魔咒", "gui.unicopia.action.no_spells_cleared": "您沒有活躍的魔咒", - "chapter.unicopia.crafting": "Spell Crafting", - "chapter.unicopia.profile": "Profile", - "chapter.unicopia.traits": "Research", - "chapter.unicopia.introduction": "Introduction", - "chapter.unicopia.fire_magic": "Fire Magic", - "chapter.unicopia.ice_magic": "Ice Magic", - "chapter.unicopia.air_magic": "Air Magic", - "chapter.unicopia.dark_magic": "Dark Magic", - "chapter.unicopia.the_otherworldly": "Forbidden Magic", - "chapter.unicopia.crystal_heart": "Artifacts", + "chapter.unicopia.crafting": "咒語合成", + "chapter.unicopia.profile": "總概", + "chapter.unicopia.traits": "研究", + "chapter.unicopia.introduction": "介紹", + "chapter.unicopia.fire_magic": "火咒", + "chapter.unicopia.ice_magic": "冰咒", + "chapter.unicopia.air_magic": "氣咒", + "chapter.unicopia.dark_magic": "暗咒", + "chapter.unicopia.the_otherworldly": "禁咒", + "chapter.unicopia.crystal_heart": "神器", "experience.unicopia.pure.magical_kindergartner": "New Blood", "experience.unicopia.impure.magical_kindergartner": "Impure", @@ -1250,19 +1286,19 @@ "experience.unicopia.corrupt.alicorn_princess": "Shadowy Alicorn Lord", "experience.unicopia.monstrous.alicorn_princess": "Dark Alicorn Lord", - "experience.unicopia.pure.polycorn_princess": "Polycorn Princess", - "experience.unicopia.impure.polycorn_princess": "Impure Polycorn Princess", - "experience.unicopia.tainted.polycorn_princess": "Tainted Polycorn Princess", - "experience.unicopia.twisted.polycorn_princess": "Fallen Polycorn Princess", - "experience.unicopia.corrupt.polycorn_princess": "Shadowy Polycorn King", - "experience.unicopia.monstrous.polycorn_princess": "Dark Polycorn King", + "experience.unicopia.pure.polycorn_princess": "多角公主", + "experience.unicopia.impure.polycorn_princess": "不潔多角公主", + "experience.unicopia.tainted.polycorn_princess": "髒污多角公主", + "experience.unicopia.twisted.polycorn_princess": "墮落多角公主", + "experience.unicopia.corrupt.polycorn_princess": "暗影多角王子", + "experience.unicopia.monstrous.polycorn_princess": "暗黑多角王子", - "experience.unicopia.pure.faustian_legend": "Hero of Legend", - "experience.unicopia.impure.faustian_legend": "Legendary", - "experience.unicopia.tainted.faustian_legend": "Storied Figure of Distant Descent", - "experience.unicopia.twisted.faustian_legend": "Dark Figure of Lore", - "experience.unicopia.corrupt.faustian_legend": "The Old God", - "experience.unicopia.monstrous.faustian_legend": "Otherworldly Terror", + "experience.unicopia.pure.faustian_legend": "史詩傳奇", + "experience.unicopia.impure.faustian_legend": "名垂青史", + "experience.unicopia.tainted.faustian_legend": "墮落傳說", + "experience.unicopia.twisted.faustian_legend": "暗黑傳說", + "experience.unicopia.corrupt.faustian_legend": "上古惡神", + "experience.unicopia.monstrous.faustian_legend": "異世魔王", "unicopia.category.name": "小馬能力", @@ -1275,16 +1311,27 @@ "key.unicopia.hud_page_up": "介面下一頁", "enchantment.unicopia.gem_finder": "尋礦", + "enchantment.unicopia.gem_finder.desc": "靠近高價值礦物時發出嗡嗡聲", "enchantment.unicopia.padded": "衝擊保護", + "enchantment.unicopia.padded.desc": "撞牆時從牆上彈開,爲您飛行護航", "enchantment.unicopia.clingy": "纏身", + "enchantment.unicopia.clingy.desc": "物品掉落後緊隨玩家", "enchantment.unicopia.repulsion": "輕盈", + "enchantment.unicopia.repulsion.desc": "身輕如燕", "enchantment.unicopia.heavy": "沉重", + "enchantment.unicopia.heavy.desc": "讓穿戴盔甲的有翼種族更沉重,更難被魔法和風推動", "enchantment.unicopia.herds": "合擊", + "enchantment.unicopia.herds.desc": "盟友更多,力量更強", "enchantment.unicopia.want_it_need_it": "爭奪詛咒", + "enchantment.unicopia.want_it_need_it.desc": "生物無法抵抗對帶此魔咒的物品的誘惑", "enchantment.unicopia.poisoned_joke": "毒笑", + "enchantment.unicopia.poisoned_joke.desc": "使用者會不時幻聽", "enchantment.unicopia.stressed": "重壓", + "enchantment.unicopia.stressed.desc": "危險時搖晃熒幕", "enchantment.unicopia.heart_bound": "赤膽忠心", + "enchantment.unicopia.heart_bound.desc": "死後物品仍然陪伴著你", "enchantment.unicopia.consumption": "經驗轉化", + "enchantment.unicopia.consumption.desc": "使用帶本魔咒的工具挖掘時,掉落物化爲經驗", "commands.race.success.self": "將自己的種族設爲%1$s", "commands.race.success": "%1$s將種族變爲%2$s", @@ -1303,16 +1350,23 @@ "commands.race.tell.other.alt": "%s是", "commands.racelist.illegal": "默認的種族%s不能在此指令中使用。", + "commands.racelist.get.allowed": "已放行(%s):", + "commands.racelist.get.not_allowed": "已攔截(%s):", + "commands.racelist.get.list_item": "- %s(%s)", + "commands.racelist.reset.success": "已清除並禁用白名單。", + "commands.racelist.reset.fail": "白名單並未啓用。無更改。", + "commands.racelist.enabled": "已啓用白名單", + "commands.racelist.disabled": "已禁用白名單", "commands.racelist.allowed": "已將%1$s加入白名單。", "commands.racelist.allowed.failed": "%1$s已在白名單內。", + "commands.racelist.inactive": "白名單並未啓用。執行/unicopia racelist <種族> 指令以對其進行配置。", "commands.racelist.disallowed": "將%1$s從白名單移除", - "commands.racelist.disallowed.failed": "%1$s不在白名單內。", + "commands.racelist.disallowed.failed": "%1$s本不在白名單內。", "commands.worldtribe.success.get": "當前所有新玩家的預設種族爲:%s", "commands.worldtribe.success.set": "將新玩家的預設種族設爲:%s", - "commands.disguise.usage": "/disguise <玩家> <實體> [nbt]", "commands.disguise.notfound": "實體ID「%s」不存在。", "commands.disguise.removed": "您的僞裝已被移除。", "commands.disguise.removed.self": "移除了自己的僞裝。", @@ -1438,6 +1492,8 @@ "death.attack.unicopia.horseshoe.self": "%1$s把自己敲死了", "death.attack.unicopia.horseshoe.item": "%1$s被%2$s用%3$s敲死了", "death.attack.unicopia.horseshoe.player": "%1$s被%2$s敲死了", + "death.attack.unicopia.spikes": "%1$s被刺死了", + "death.attack.unicopia.spikes.player": "%1$s逃離%2$s時萬刺攻心", "death.fell.accident.ladder.pegasus": "%1$s忘記了自己能飛,掉下了梯子", "death.fell.accident.vines.pegasus": "%1$s忘記了自己能飛,掉下了藤蔓", @@ -1492,6 +1548,7 @@ "unicopia.subtitle.pegasus.molt": "飛馬:掉落羽毛", "unicopia.subtitle.unicorn.teleport": "魔法:傳送", "unicopia.subtitle.player.wololo": "喔囉囉!", + "unicopia.subtitle.corrupt": "魔法:墮落", "unicopia.subtitle.entity.player.whistle": "玩家:吹口哨", "unicopia.subtitle.entity.player.kick": "玩家:踢", "unicopia.subtitle.magic_aura": "魔法:低鳴", @@ -1544,13 +1601,13 @@ "advancements.unicopia.lightning_bug.description": "被雷劈十次", "advancements.unicopia.jar.title": "哇,這是什麼?", "advancements.unicopia.jar.description": "找到一個空罐子", - "advancements.unicopia.gotcha.title": "抓到!", + "advancements.unicopia.gotcha.title": "抓到你了!", "advancements.unicopia.gotcha.description": "捕獲暴雨", "advancements.unicopia.trick_apple.title": "無序林檎", "advancements.unicopia.trick_apple.description": "找到你的第一個彩虹蘋果", - "advancements.unicopia.feed_trick_apple.title": "來,試試這個", + "advancements.unicopia.feed_trick_apple.title": "餐廳珍饈", "advancements.unicopia.feed_trick_apple.description": "將彩虹蘋果喂給其他生物", - "advancements.unicopia.eat_trick_apple.title": "酥脆", + "advancements.unicopia.eat_trick_apple.title": "烤得酥脆", "advancements.unicopia.eat_trick_apple.description": "吃下彩虹蘋果", "advancements.unicopia.eat_pinecone.title": "走投無路", "advancements.unicopia.eat_pinecone.description": "吃下松果", @@ -1569,7 +1626,7 @@ "advancements.unicopia.burn_juice.title": "不太對勁", "advancements.unicopia.burn_juice.description": "將蘋果汁烤糊", - "advancements.unicopia.apple_route.title": "蘋果、蘋果、蘋果", + "advancements.unicopia.apple_route.title": "林檎傳說", "advancements.unicopia.apple_route.description": "開啓你的蘋果傳奇遊記", "advancements.unicopia.juice.title": "清爽", "advancements.unicopia.juice.description": "這些蘋果終於有用了", @@ -1639,7 +1696,7 @@ "advancements.unicopia.a_falling_wizard.description": "一個施飛行咒失敗的獨角", "advancements.unicopia.split_the_sea.title": "你叫什麼,摩西嗎?", - "advancements.unicopia.split_the_sea.description": "用魔法一次性分開一百方塊以上的水", + "advancements.unicopia.split_the_sea.description": "用魔法一次分開一百方塊以上的水", "advancements.unicopia.save_the_day.title": "拯救世界", "advancements.unicopia.save_the_day.description": "擊敗黑晶王", "advancements.unicopia.ascension.title": "原地昇天", diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_arrow.png b/src/main/resources/assets/unicopia/textures/item/gemstone_arrow.png new file mode 100644 index 00000000..e51a73ae Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_arrow.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_brush.png b/src/main/resources/assets/unicopia/textures/item/gemstone_brush.png new file mode 100644 index 00000000..fb7ebb21 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_brush.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_cross.png b/src/main/resources/assets/unicopia/textures/item/gemstone_cross.png new file mode 100644 index 00000000..c8670f00 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_cross.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_donut.png b/src/main/resources/assets/unicopia/textures/item/gemstone_donut.png new file mode 100644 index 00000000..4a47ebf5 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_donut.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_flame.png b/src/main/resources/assets/unicopia/textures/item/gemstone_flame.png new file mode 100644 index 00000000..f2b992ea Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_flame.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_ice.png b/src/main/resources/assets/unicopia/textures/item/gemstone_ice.png new file mode 100644 index 00000000..284fa195 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_ice.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_lambda.png b/src/main/resources/assets/unicopia/textures/item/gemstone_lambda.png new file mode 100644 index 00000000..2dc1d0e7 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_lambda.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_ring.png b/src/main/resources/assets/unicopia/textures/item/gemstone_ring.png new file mode 100644 index 00000000..e6e4aebd Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_ring.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_rocket.png b/src/main/resources/assets/unicopia/textures/item/gemstone_rocket.png new file mode 100644 index 00000000..a3c24a9d Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_rocket.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_pure.png b/src/main/resources/assets/unicopia/textures/item/gemstone_round.png similarity index 100% rename from src/main/resources/assets/unicopia/textures/item/gemstone_pure.png rename to src/main/resources/assets/unicopia/textures/item/gemstone_round.png diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_shield.png b/src/main/resources/assets/unicopia/textures/item/gemstone_shield.png new file mode 100644 index 00000000..2395fc6f Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_shield.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_skull.png b/src/main/resources/assets/unicopia/textures/item/gemstone_skull.png new file mode 100644 index 00000000..9da15bdd Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_skull.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_splint.png b/src/main/resources/assets/unicopia/textures/item/gemstone_splint.png new file mode 100644 index 00000000..8983ce9a Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_splint.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_star.png b/src/main/resources/assets/unicopia/textures/item/gemstone_star.png new file mode 100644 index 00000000..35d63424 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_star.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_triangle.png b/src/main/resources/assets/unicopia/textures/item/gemstone_triangle.png new file mode 100644 index 00000000..e1cec73f Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_triangle.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_vortex.png b/src/main/resources/assets/unicopia/textures/item/gemstone_vortex.png new file mode 100644 index 00000000..c367d217 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_vortex.png differ diff --git a/src/main/resources/assets/unicopia/textures/item/gemstone_wave.png b/src/main/resources/assets/unicopia/textures/item/gemstone_wave.png new file mode 100644 index 00000000..eaeb6f4a Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/item/gemstone_wave.png differ diff --git a/src/main/resources/data/minecraft/tags/damage_type/bypasses_armor.json b/src/main/resources/data/minecraft/tags/damage_type/bypasses_armor.json index 9f715f8f..d2722662 100644 --- a/src/main/resources/data/minecraft/tags/damage_type/bypasses_armor.json +++ b/src/main/resources/data/minecraft/tags/damage_type/bypasses_armor.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "unicopia:magical_exhaustion", + "unicopia:gravity_well_recoil", "unicopia:alicorn_amulet", "unicopia:zap", "unicopia:kick", diff --git a/src/main/resources/unicopia.aw b/src/main/resources/unicopia.aw index d70347c0..708479ac 100644 --- a/src/main/resources/unicopia.aw +++ b/src/main/resources/unicopia.aw @@ -6,9 +6,6 @@ accessible class net/minecraft/client/render/item/HeldItemRenderer$H accessible class net/minecraft/client/render/VertexConsumers$Union accessible class net/minecraft/client/gui/hud/InGameHud$HeartType -accessible method net/minecraft/world/GameRules register (Ljava/lang/String;Lnet/minecraft/world/GameRules$Category;Lnet/minecraft/world/GameRules$Type;)Lnet/minecraft/world/GameRules$Key; -accessible method net/minecraft/world/GameRules$BooleanRule create (Z)Lnet/minecraft/world/GameRules$Type; -accessible method net/minecraft/world/GameRules$IntRule create (I)Lnet/minecraft/world/GameRules$Type; accessible method net/minecraft/world/gen/foliage/FoliagePlacerType (Lcom/mojang/serialization/Codec;)V accessible field net/minecraft/entity/mob/CreeperEntity CHARGED Lnet/minecraft/entity/data/TrackedData;