Merge branch '1.20.1' into 1.20.2

# Conflicts:
#	gradle.properties
This commit is contained in:
Sollace 2024-04-11 13:21:08 +01:00
commit 7abe3e4260
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
85 changed files with 1051 additions and 656 deletions

View file

@ -124,6 +124,6 @@
这些状态是按周期循环的,如果您发现的果树不是您想要的状态,可以在它旁边等待几天直到结果,但请不要在魔虹苹果成熟前收获它们,否则它们会把您电得酥脆! 这些状态是按周期循环的,如果您发现的果树不是您想要的状态,可以在它旁边等待几天直到结果,但请不要在魔虹苹果成熟前收获它们,否则它们会把您电得酥脆!
如果您设法获取到了魔虹苹果的木头和叶子,那它们也可以充当威慑滋事者的完美屏障。 如果您设法获取到了魔虹苹果的木头和叶子,那它们也可以充当威慑滋事者的完美屏障。
### ###
香软可口,猪猪最爱。 香软可口,猪猪最爱。

3
crowdin.yml Normal file
View file

@ -0,0 +1,3 @@
files:
- source: src/main/resources/assets/unicopia/lang/en_us.json
translation: /%original_path%/%locale_with_underscore%.%file_extension%

View file

@ -23,7 +23,7 @@ org.gradle.daemon=false
fabwork_version=1.3.0+1.20.2 fabwork_version=1.3.0+1.20.2
modmenu_version=8.0.0-beta.1 modmenu_version=8.0.0-beta.1
minelp_version=4.11.6+1.20.2 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 reach_attributes_version=2.3.4
trinkets_version=3.8.0 trinkets_version=3.8.0
terraformer_api_version=8.0.0-beta.1 terraformer_api_version=8.0.0-beta.1

View file

@ -1,12 +1,18 @@
package com.minelittlepony.unicopia; 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), GOOD(Formatting.BLUE, -1, 0),
NEUTRAL(Formatting.LIGHT_PURPLE, 0, 0.5F), NEUTRAL(Formatting.LIGHT_PURPLE, 0, 0.5F),
BAD(Formatting.RED, 1, 1); BAD(Formatting.RED, 1, 1);
@SuppressWarnings("deprecation")
public static final EnumCodec<Affinity> CODEC = StringIdentifiable.createCodec(Affinity::values);
private final Formatting color; private final Formatting color;
private final int corruption; private final int corruption;
@ -20,6 +26,11 @@ public enum Affinity {
this.alignment = alignment; this.alignment = alignment;
} }
@Override
public String asString() {
return name().toLowerCase(Locale.ROOT);
}
public Formatting getColor() { public Formatting getColor() {
return color; return color;
} }

View file

@ -1,10 +1,24 @@
package com.minelittlepony.unicopia; package com.minelittlepony.unicopia;
public enum Availability { import java.util.Locale;
import net.minecraft.util.StringIdentifiable;
public enum Availability implements StringIdentifiable {
DEFAULT, DEFAULT,
COMMANDS, COMMANDS,
NONE; NONE;
@SuppressWarnings("deprecation")
public static final EnumCodec<Availability> CODEC = StringIdentifiable.createCodec(Availability::values);
private final String name = name().toLowerCase(Locale.ROOT);
@Override
public String asString() {
return name;
}
public boolean isSelectable() { public boolean isSelectable() {
return this == DEFAULT; return this == DEFAULT;
} }

View file

@ -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("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."); .addComment("The result will always be what is set by this config file.");
public final Setting<Boolean> toggleAbilityKeys = value("client", "toggleAbilityKeys", false)
.addComment("If true the ability keybinds will function as toggle keys rather than hold keys");
public final Setting<Integer> hudPage = value("client", "hudActivePage", 0) public final Setting<Integer> 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)"); .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)");

View file

@ -1,15 +1,28 @@
package com.minelittlepony.unicopia; package com.minelittlepony.unicopia;
import java.util.Locale;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.util.StringIdentifiable;
public enum FlightType { public enum FlightType implements StringIdentifiable {
UNSET, UNSET,
NONE, NONE,
AVIAN, AVIAN,
INSECTOID, INSECTOID,
ARTIFICIAL; ARTIFICIAL;
@SuppressWarnings("deprecation")
public static final EnumCodec<FlightType> CODEC = StringIdentifiable.createCodec(FlightType::values);
private final String name = name().toLowerCase(Locale.ROOT);
@Override
public String asString() {
return name;
}
public boolean isGrounded() { public boolean isGrounded() {
return this == NONE; return this == NONE;
} }

View file

@ -53,7 +53,7 @@ public interface Owned<E extends Entity> {
} }
default boolean hasCommonOwner(Owned<?> sibling) { default boolean hasCommonOwner(Owned<?> sibling) {
return getMasterId().isPresent() && getMasterId().equals(sibling.getMasterId()); return getMasterId().equals(sibling.getMasterId());
} }
interface Mutable<E extends Entity> { interface Mutable<E extends Entity> {

View file

@ -1,20 +1,21 @@
package com.minelittlepony.unicopia; package com.minelittlepony.unicopia;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; 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.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.ability.magic.Affine;
import com.minelittlepony.unicopia.util.RegistryUtils; import com.minelittlepony.unicopia.util.RegistryUtils;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; 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.command.argument.RegistryKeyArgumentType;
import net.minecraft.entity.player.PlayerEntity; 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.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
public record Race (Supplier<Composite> compositeSupplier, Availability availability, boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) implements Affine { public record Race (
List<Ability<?>> 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 String DEFAULT_ID = "unicopia:unset";
public static final Registry<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID); public static final Registry<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID);
public static final Registry<Race> COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID); public static final Registry<Race> COMMAND_REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race/grantable"), DEFAULT_ID);
public static final RegistryKey<? extends Registry<Race>> REGISTRY_KEY = REGISTRY.getKey(); public static final RegistryKey<? extends Registry<Race>> 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<Race, Composite> 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) { public static final Codec<Race> CODEC = RecordCodecBuilder.create(i -> i.group(
return register(Unicopia.id(name), availability, magic, flight, earth, nocturnal, canHang); Abilities.REGISTRY.getCodec().listOf().fieldOf("abilities").forGetter(Race::abilities),
} Affinity.CODEC.fieldOf("affinity").forGetter(Race::affinity),
Availability.CODEC.fieldOf("availability").forGetter(Race::availability),
public static Race register(Identifier id, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { FlightType.CODEC.fieldOf("flight").forGetter(Race::flightType),
Race race = Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null, null)), availability, magic, flight, earth, nocturnal, canHang)); Codec.BOOL.fieldOf("magic").forGetter(Race::canCast),
if (availability.isGrantable()) { Codec.BOOL.fieldOf("can_forage").forGetter(Race::hasIronGut),
Registry.register(COMMAND_REGISTRY, id, race); Codec.BOOL.fieldOf("earth_pony_strength").forGetter(Race::canUseEarth),
} Codec.BOOL.fieldOf("nocturnal").forGetter(Race::isNocturnal),
return race; Codec.BOOL.fieldOf("hanging").forGetter(Race::canHang),
} Codec.BOOL.fieldOf("aquatic").forGetter(Race::isFish),
Codec.BOOL.fieldOf("weather_magic").forGetter(Race::canInfluenceWeather),
public static RegistryKeyArgumentType<Race> argument() { Codec.BOOL.fieldOf("cloud_magic").forGetter(Race::canInteractWithClouds)
return RegistryKeyArgumentType.registryKey(COMMAND_REGISTRY.getKey()); ).apply(i, Race::new));
}
/** /**
* The default, unset race. * The default, unset race.
* This is used if there are no other races. * 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 UNSET = register("unset", new Builder().availability(Availability.COMMANDS));
public static final Race HUMAN = register("human", Availability.COMMANDS, false, FlightType.NONE, false, false, false); public static final Race HUMAN = register("human", new Builder().availability(Availability.COMMANDS));
public static final Race EARTH = register("earth", Availability.DEFAULT, false, FlightType.NONE, true, false, false); public static final Race EARTH = register("earth", new Builder().foraging().earth()
public static final Race UNICORN = register("unicorn", Availability.DEFAULT, true, FlightType.NONE, false, false, false); .abilities(Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW)
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 UNICORN = register("unicorn", new Builder().foraging().magic()
public static final Race ALICORN = register("alicorn", Availability.COMMANDS, true, FlightType.AVIAN, true, false, false); .abilities(Abilities.TELEPORT, Abilities.CAST, Abilities.GROUP_TELEPORT, Abilities.SHOOT, Abilities.DISPELL)
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 PEGASUS = register("pegasus", new Builder().foraging().flight(FlightType.AVIAN).weatherMagic().cloudMagic()
public static final Race HIPPOGRIFF = register("hippogriff", Availability.DEFAULT, false, FlightType.AVIAN, false, false, false); .abilities(Abilities.TOGGLE_FLIGHT, Abilities.RAINBOOM, Abilities.CAPTURE_CLOUD, Abilities.CARRY)
public static final Race SEAPONY = register("seapony", Availability.NONE, false, FlightType.NONE, false, false, false); );
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 static void bootstrap() {}
public Composite composite() { public Composite composite() {
return compositeSupplier.get(); return COMPOSITES.apply(this);
} }
public Composite composite(@Nullable Race pseudo, @Nullable Race potential) { public Composite composite(@Nullable Race pseudo, @Nullable Race potential) {
@ -76,11 +114,7 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
@Override @Override
public Affinity getAffinity() { public Affinity getAffinity() {
return this == CHANGELING ? Affinity.BAD : Affinity.NEUTRAL; return affinity;
}
public boolean hasIronGut() {
return !isHuman();
} }
public boolean isUnset() { public boolean isUnset() {
@ -91,12 +125,8 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return !isHuman(); return !isHuman();
} }
public boolean isFish() {
return this == SEAPONY;
}
public boolean isHuman() { public boolean isHuman() {
return this == UNSET || this == HUMAN; return isUnset() || this == HUMAN;
} }
public boolean isDayurnal() { public boolean isDayurnal() {
@ -107,18 +137,14 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return !flightType().isGrounded(); return !flightType().isGrounded();
} }
public boolean canInteractWithClouds() {
return canFly() && this != CHANGELING;
}
public boolean canInfluenceWeather() {
return canFly() && this != CHANGELING && this != BAT && this != HIPPOGRIFF;
}
public boolean hasPersistentWeatherMagic() { public boolean hasPersistentWeatherMagic() {
return canInfluenceWeather(); return canInfluenceWeather();
} }
public boolean canUse(Ability<?> ability) {
return abilities.contains(ability);
}
public Identifier getId() { public Identifier getId() {
return REGISTRY.getId(this); return REGISTRY.getId(this);
} }
@ -132,13 +158,11 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
} }
public String getTranslationKey() { public String getTranslationKey() {
Identifier id = getId(); return Util.createTranslationKey("race", getId());
return String.format("%s.race.%s", id.getNamespace(), id.getPath().toLowerCase());
} }
public Identifier getIcon() { public Identifier getIcon() {
Identifier id = getId(); return getId().withPath(p -> "textures/gui/race/" + p + ".png");
return new Identifier(id.getNamespace(), "textures/gui/race/" + id.getPath() + ".png");
} }
public boolean isPermitted(@Nullable PlayerEntity sender) { public boolean isPermitted(@Nullable PlayerEntity sender) {
@ -161,16 +185,6 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return isEquine() ? this : other; 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 @Override
public String toString() { public String toString() {
return "Race{ " + getId().toString() + " }"; return "Race{ " + getId().toString() + " }";
@ -195,13 +209,29 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return def; return def;
} }
public static Race fromName(String name) { public static Race register(String name, Builder builder) {
return fromName(name, EARTH); 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<Race> argument() {
return RegistryKeyArgumentType.registryKey(COMMAND_REGISTRY.getKey());
} }
public static Race fromArgument(CommandContext<ServerCommandSource> context, String name) throws CommandSyntaxException { public static Race fromArgument(CommandContext<ServerCommandSource> context, String name) throws CommandSyntaxException {
Identifier id = context.getArgument(name, RegistryKey.class).getValue(); 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<Race> allPermitted(PlayerEntity player) { public static Set<Race> allPermitted(PlayerEntity player) {
@ -233,6 +263,10 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return any(Race::canCast); return any(Race::canCast);
} }
public boolean canUse(Ability<?> ability) {
return any(r -> r.canUse(ability));
}
public boolean canInteractWithClouds() { public boolean canInteractWithClouds() {
return any(Race::canInteractWithClouds); return any(Race::canInteractWithClouds);
} }
@ -252,6 +286,85 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return physical().flightType().or(pseudo().flightType()); return physical().flightType().or(pseudo().flightType());
} }
} }
public static final class Builder {
private final List<Ability<?>> 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);
}
}
} }

View file

@ -42,8 +42,8 @@ public interface WeaklyOwned<E extends Entity> extends Owned<E>, WorldConvertabl
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
default void setMaster(Owned<? extends E> sibling) { default void setMaster(Owned<? extends E> sibling) {
if (sibling instanceof WeaklyOwned) { if (sibling instanceof WeaklyOwned w) {
getMasterReference().copyFrom(((WeaklyOwned<E>)sibling).getMasterReference()); getMasterReference().copyFrom(w.getMasterReference());
} else { } else {
setMaster(sibling.getMaster()); setMaster(sibling.getMaster());
} }

View file

@ -68,7 +68,9 @@ public interface Ability<T extends Hit> {
* Checks if the given race is permitted to use this ability * Checks if the given race is permitted to use this ability
* @param playerSpecies The player's species * @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. * 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.

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -11,17 +10,11 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
abstract class AbstractSpellCastingAbility implements Ability<Hit> { abstract class AbstractSpellCastingAbility implements Ability<Hit> {
@Override @Override
public int getCooldownTime(Pony player) { public int getCooldownTime(Pony player) {
return 0; return 0;
} }
@Override
public boolean canUse(Race race) {
return race.canCast() && race != Race.KIRIN;
}
@Override @Override
public Text getName(Pony player) { public Text getName(Pony player) {
CustomisedSpellType<?> spell = player.getCharms().getEquippedSpell(player.getCharms().getHand()); CustomisedSpellType<?> spell = player.getCharms().getEquippedSpell(player.getCharms().getHand());

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
@ -16,11 +15,6 @@ import net.minecraft.world.event.GameEvent;
public class BatEeeeAbility extends ScreechAbility { public class BatEeeeAbility extends ScreechAbility {
public static final int SELF_SPOOK_PROBABILITY = 20000; public static final int SELF_SPOOK_PROBABILITY = 20000;
@Override
public boolean canUse(Race race) {
return race == Race.BAT;
}
@Override @Override
protected void playSounds(Pony player, Random rng, float strength) { protected void playSounds(Pony player, Random rng, float strength) {
int count = 1 + rng.nextInt(10) + (int)(strength * 10); int count = 1 + rng.nextInt(10) + (int)(strength * 10);

View file

@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Multi; import com.minelittlepony.unicopia.ability.data.Multi;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.TraceHelper; import com.minelittlepony.unicopia.util.TraceHelper;
@ -30,11 +29,6 @@ public class BatPonyHangAbility implements Ability<Multi> {
return 0; return 0;
} }
@Override
public boolean canUse(Race race) {
return race == Race.BAT;
}
@Override @Override
public Optional<Multi> prepare(Pony player) { public Optional<Multi> prepare(Pony player) {

View file

@ -6,7 +6,6 @@ import java.util.UUID;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -37,11 +36,6 @@ public class CarryAbility implements Ability<Hit> {
return 0; return 0;
} }
@Override
public boolean canUse(Race race) {
return race.canFly();
}
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.INSTANCE; return Hit.INSTANCE;

View file

@ -7,7 +7,6 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
@ -48,11 +47,6 @@ public class ChangelingFeedAbility implements Ability<Hit> {
return !SpellType.FEED.isOn(player) && ChangelingFeedingSpell.canFeed(player) ? 15 : 80; return !SpellType.FEED.isOn(player) && ChangelingFeedingSpell.canFeed(player) ? 15 : 80;
} }
@Override
public boolean canUse(Race race) {
return race == Race.CHANGELING;
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
@ -48,11 +47,6 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
return 50; return 50;
} }
@Override
public boolean canUse(Race race) {
return race.canUseEarth();
}
@Override @Override
public Optional<Pos> prepare(Pony player) { public Optional<Pos> prepare(Pony player) {
return TraceHelper.findBlock(player.asEntity(), 3, 1).map(Pos::new); return TraceHelper.findBlock(player.asEntity(), 3, 1).map(Pos::new);

View file

@ -53,11 +53,6 @@ public class EarthPonyKickAbility implements Ability<Pos> {
return 50; return 50;
} }
@Override
public boolean canUse(Race race) {
return race.canUseEarth();
}
@Override @Override
public Identifier getIcon(Pony player) { public Identifier getIcon(Pony player) {
return getId().withPath(p -> "textures/gui/ability/" + p return getId().withPath(p -> "textures/gui/ability/" + p

View file

@ -62,11 +62,6 @@ public class EarthPonyStompAbility implements Ability<Hit> {
return 50; return 50;
} }
@Override
public boolean canUse(Race race) {
return race.canUseEarth();
}
@Override @Override
public Identifier getIcon(Pony player) { public Identifier getIcon(Pony player) {
Identifier id = Abilities.REGISTRY.getId(this); Identifier id = Abilities.REGISTRY.getId(this);

View file

@ -4,7 +4,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -23,11 +22,6 @@ public class FlyingDashAbility implements Ability<Hit> {
return 30; return 30;
} }
@Override
public boolean canUse(Race race) {
return race == Race.HIPPOGRIFF;
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.Living; 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! * Ability to hug mobs. Not all of them are receptive to your advances though, so be careful!
*/ */
public class HugAbility extends CarryAbility { public class HugAbility extends CarryAbility {
@Override
public boolean canUse(Race race) {
return race.canUseEarth();
}
@Override @Override
public boolean apply(Pony pony, Hit data) { public boolean apply(Pony pony, Hit data) {
PlayerEntity player = pony.asEntity(); PlayerEntity player = pony.asEntity();

View file

@ -1,16 +1,10 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
public class KirinCastingAbility extends UnicornCastingAbility { public class KirinCastingAbility extends UnicornCastingAbility {
@Override
public boolean canUse(Race race) {
return race == Race.KIRIN;
}
@Override @Override
public void coolDown(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.spawnParticles(ParticleTypes.FLAME, 5); player.spawnParticles(ParticleTypes.FLAME, 5);

View file

@ -4,7 +4,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
@ -30,11 +29,6 @@ public class KirinRageAbility implements Ability<Hit> {
return 60; return 60;
} }
@Override
public boolean canUse(Race race) {
return race == Race.KIRIN;
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -5,7 +5,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient;
@ -36,11 +35,6 @@ public class NirikBlastAbility implements Ability<Hit> {
return 3; return 3;
} }
@Override
public boolean canUse(Race race) {
return race == Race.KIRIN;
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Numeric; import com.minelittlepony.unicopia.ability.data.Numeric;
@ -54,11 +53,6 @@ public class PeckAbility implements Ability<Hit> {
return true; return true;
} }
@Override
public boolean canUse(Race race) {
return race == Race.HIPPOGRIFF;
}
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.INSTANCE; return Hit.INSTANCE;

View file

@ -4,7 +4,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
@ -33,11 +32,6 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
return 6; return 6;
} }
@Override
public boolean canUse(Race race) {
return race.canInfluenceWeather();
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -4,7 +4,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
@ -26,11 +25,6 @@ public class PegasusRainboomAbility implements Ability<Hit> {
return 60; return 60;
} }
@Override
public boolean canUse(Race race) {
return race.canInfluenceWeather();
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.data.Numeric; import com.minelittlepony.unicopia.ability.data.Numeric;
@ -49,11 +48,6 @@ public class ScreechAbility implements Ability<Numeric> {
return true; return true;
} }
@Override
public boolean canUse(Race race) {
return race == Race.HIPPOGRIFF;
}
@Override @Override
public Optional<Numeric> prepare(Pony player) { public Optional<Numeric> prepare(Pony player) {
return player.getAbilities().getActiveStat() return player.getAbilities().getActiveStat()

View file

@ -5,7 +5,6 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UPOIs; import com.minelittlepony.unicopia.UPOIs;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
@ -38,11 +37,6 @@ public class SeaponySonarPulseAbility implements Ability<Hit> {
return 100; return 100;
} }
@Override
public boolean canUse(Race race) {
return race == Race.SEAPONY;
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -12,11 +12,6 @@ import com.minelittlepony.unicopia.server.world.UGameRules;
public class TimeChangeAbility implements Ability<Rot> { public class TimeChangeAbility implements Ability<Rot> {
@Override
public boolean canUse(Race race) {
return race == Race.ALICORN;
}
@Override @Override
public boolean canUse(Race.Composite race) { public boolean canUse(Race.Composite race) {
return canUse(race.physical()) || race.pseudo() == Race.UNICORN; return canUse(race.physical()) || race.pseudo() == Race.UNICORN;

View file

@ -24,11 +24,6 @@ public class ToggleFlightAbility implements Ability<Hit> {
return 0; return 0;
} }
@Override
public boolean canUse(Race race) {
return race.canFly();
}
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {

View file

@ -33,11 +33,6 @@ public class UnicornDispellAbility implements Ability<Pos> {
return 0; return 0;
} }
@Override
public boolean canUse(Race race) {
return race.canCast() || race == Race.CHANGELING;
}
@Override @Override
public int getColor(Pony player) { public int getColor(Pony player) {
return SpellType.PORTAL.getColor(); return SpellType.PORTAL.getColor();

View file

@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.data.Pos;
@ -60,11 +59,6 @@ public class UnicornTeleportAbility implements Ability<Pos> {
return (int)(50 - Math.min(45F, player.getLevel().get() * 0.75F)); return (int)(50 - Math.min(45F, player.getLevel().get() * 0.75F));
} }
@Override
public boolean canUse(Race race) {
return race.canCast() && race != Race.KIRIN;
}
@Override @Override
public double getCostEstimate(Pony player) { public double getCostEstimate(Pony player) {
return prepare(player).map(pos -> pos.distanceTo(player) / 10).orElse(0D); return prepare(player).map(pos -> pos.distanceTo(player) / 10).orElse(0D);

View file

@ -98,7 +98,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
@Override @Override
public boolean isDead() { public boolean isDead() {
return dead && deathTicks <= 0; return dead && deathTicks <= 0 && super.isDead();
} }
@Override @Override

View file

@ -1,8 +1,12 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.USounds; 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.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; 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.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; 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.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils; 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.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate; 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 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.Entity;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.PersistentProjectileEntity; import net.minecraft.entity.projectile.PersistentProjectileEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates; 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. * 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() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.CHAOS, 5) .with(Trait.CHAOS, 5)
.with(Trait.KNOWLEDGE, 1) .with(Trait.KNOWLEDGE, 1)
@ -49,18 +58,31 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega
private float accumulatedMass = 0; 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) { protected DarkVortexSpell(CustomisedSpellType<?> type) {
super(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 double getEventHorizonRadius() {
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) { return radius.getValue();
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 getDrawDropOffRange() {
return getEventHorizonRadius() * 20;
}
private double getAttractiveForce(Caster<?> source, Entity target) {
return AttractionUtils.getAttractiveForce(getMass(), getOrigin(source), target);
} }
@Override @Override
@ -79,22 +101,102 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega
return true; 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) { if (source.asEntity().age % 20 == 0) {
source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_ADDITIONS, SoundCategory.AMBIENT, 1, 1); source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_ADDITIONS, SoundCategory.AMBIENT, 1, 1);
} }
if (!source.isClient() && source.asWorld().random.nextInt(300) == 0) { double eventHorizon = getEventHorizonRadius();
ParticleUtils.spawnParticle(source.asWorld(), LightningBoltParticleEffect.DEFAULT, getOrigin(source), Vec3d.ZERO);
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; return true;
} }
@Override @Override
protected void consumeManage(Caster<?> source, long costMultiplier, float knowledge) { public void tickDying(Caster<?> source) {
if (!source.subtractEnergyCost(-accumulatedMass)) { accumulatedMass -= 0.8F;
setDead(); 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; return accumulatedMass < 4;
} }
@Override private boolean isValidTarget(Caster<?> source, Entity entity) {
protected boolean isValidTarget(Caster<?> source, Entity entity) {
return EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(entity) && getAttractiveForce(source, entity) > 0; return EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(entity) && getAttractiveForce(source, entity) > 0;
} }
@Override public Vec3d getOrigin(Caster<?> source) {
public void generateParticles(Caster<?> source) { return source.asEntity().getPos().add(0, getYOffset(), 0);
super.generateParticles(source);
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
);
}
});
}
} }
@Override public double getYOffset() {
public double getDrawDropOffRange(Caster<?> source) { return 2;
return getEventHorizonRadius() * 20;
} }
@Override private boolean canAffect(Caster<?> source, BlockPos pos) {
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);
});
}
});
}
}
return super.applyEntities(source);
}
protected boolean canAffect(Caster<?> source, BlockPos pos) {
return source.canModifyAt(pos) return source.canModifyAt(pos)
&& source.asWorld().getFluidState(pos).isEmpty() && source.asWorld().getBlockState(pos).getHardness(source.asWorld(), pos) >= 0
&& source.asWorld().getBlockState(pos).getHardness(source.asWorld(), pos) >= 0; && !source.asWorld().getBlockState(pos).isIn(UTags.Blocks.CATAPULT_IMMUNE);
} }
// 1. force decreases with distance: distance scale 1 -> 0 private void affectBlock(Caster<?> source, BlockPos pos, Vec3d origin) {
// 2. max force (at dist 0) is taken from accumulated mass if (!canAffect(source, pos)) {
// 3. force reaches 0 at distance of drawDropOffRange if (source.asWorld().getBlockState(pos).isOf(Blocks.BEDROCK)) {
source.asWorld().setBlockState(pos, Blocks.BARRIER.getDefaultState());
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; return;
} }
if (pos.isWithinDistance(origin, getEventHorizonRadius())) {
if (distance <= getEventHorizonRadius() + 0.5) { source.asWorld().breakBlock(pos, false);
target.setVelocity(target.getVelocity().multiply(distance / (2 * radius))); updateStatePostRemoval(source, pos);
if (distance < 1) { } else {
target.setVelocity(target.getVelocity().multiply(distance)); CatapultSpell.createBlockEntity(source.asWorld(), pos, e -> {
updateStatePostRemoval(source, pos);
e.addVelocity(0, 0.1, 0);
});
} }
}
private void updateStatePostRemoval(Caster<?> source, BlockPos pos) {
if (!source.asWorld().getFluidState(pos).isEmpty()) {
source.asWorld().setBlockState(pos, Blocks.AIR.getDefaultState());
}
}
private void affectEntity(Caster<?> source, Entity target, Vec3d origin) {
double distance = target.getPos().distanceTo(origin);
double eventHorizonRadius = getEventHorizonRadius();
if (distance <= eventHorizonRadius + 0.5) {
target.setVelocity(target.getVelocity().multiply(distance < 1 ? distance : distance / (2 * eventHorizonRadius)));
Living.updateVelocity(target); Living.updateVelocity(target);
@Nullable @Nullable
@ -227,20 +281,22 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega
target.damage(source.damageOf(UDamageTypes.GAVITY_WELL_RECOIL, source), Integer.MAX_VALUE); target.damage(source.damageOf(UDamageTypes.GAVITY_WELL_RECOIL, source), Integer.MAX_VALUE);
if (!(target instanceof PlayerEntity)) { if (!(target instanceof PlayerEntity)) {
target.discard(); 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()) { if (target.isAlive()) {
target.damage(source.asEntity().getDamageSources().outOfWorld(), Integer.MAX_VALUE); target.damage(source.asEntity().getDamageSources().outOfWorld(), Integer.MAX_VALUE);
} }
source.subtractEnergyCost(-massOfTarget * 10); 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 { } else {
double force = getAttractiveForce(source, target); double force = getAttractiveForce(source, target);
AttractionUtils.applyForce(getOrigin(source), target, -force, 0, true); AttractionUtils.applyForce(origin, target, -force, 0, true);
source.subtractEnergyCost(-2);
} }
} }

View file

@ -197,7 +197,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
} }
Equine.of(minion).filter(eq -> eq instanceof Creature).ifPresent(eq -> { 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)) { if (source.asWorld().random.nextFloat() < source.getCorruption().getScaled(1)) {
((Creature)eq).setDiscorded(true); ((Creature)eq).setDiscorded(true);
} }

View file

@ -57,7 +57,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
} }
public boolean isLinked() { public boolean isLinked() {
return teleportationTarget.getTarget().isPresent(); return teleportationTarget.isSet();
} }
public Optional<EntityReference.EntityValues<Entity>> getTarget() { public Optional<EntityReference.EntityValues<Entity>> getTarget() {
@ -85,7 +85,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Optional<Ether.Entry<PortalSpell>> getTarget(Caster<?> source) { private Optional<Ether.Entry<PortalSpell>> getDestination(Caster<?> source) {
return getTarget().map(target -> Ether.get(source.asWorld()).get((SpellType<PortalSpell>)getType(), target, targetPortalId)); return getTarget().map(target -> Ether.get(source.asWorld()).get((SpellType<PortalSpell>)getType(), target, targetPortalId));
} }
@ -98,13 +98,12 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
if (situation == Situation.GROUND) { if (situation == Situation.GROUND) {
if (source.isClient()) { if (source.isClient()) {
source.spawnParticles(particleArea, 5, pos -> { source.spawnParticles(particleArea, 5, pos -> {
source.addParticle(ParticleTypes.ELECTRIC_SPARK, pos, Vec3d.ZERO); source.addParticle(ParticleTypes.ELECTRIC_SPARK, pos, Vec3d.ZERO);
}); });
} else { } else {
getTarget().ifPresent(target -> { teleportationTarget.getTarget().ifPresent(target -> {
if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) == null) { if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) == null) {
Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + target.uuid()); Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + target.uuid());
teleportationTarget.set(null); 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), entry -> tickWithTargetLink(source, entry),
() -> findLink(source) () -> 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.pitch = pitch;
entry.yaw = yaw; entry.yaw = yaw;
Ether.get(source.asWorld()).markDirty(); ether.markDirty();
} }
return !isDead(); return !isDead();
@ -185,8 +185,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
} }
Ether.get(source.asWorld()).anyMatch(getType(), entry -> { Ether.get(source.asWorld()).anyMatch(getType(), entry -> {
if (entry.isAvailable() && !entry.entity.referenceEquals(source.asEntity()) && entry.entity.isSet()) { if (!entry.entity.referenceEquals(source.asEntity()) && entry.claim()) {
entry.setTaken(true);
teleportationTarget.copyFrom(entry.entity); teleportationTarget.copyFrom(entry.entity);
targetPortalId = entry.getSpellId(); targetPortalId = entry.getSpellId();
setDirty(); setDirty();
@ -216,9 +215,8 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
Ether ether = Ether.get(caster.asWorld()); Ether.get(caster.asWorld()).remove(getType(), caster);
ether.remove(getType(), caster); getDestination(caster).ifPresent(Ether.Entry::release);
getTarget(caster).ifPresent(e -> e.setTaken(false));
} }
@Override @Override

View file

@ -1,10 +1,5 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; 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 org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Affinity; 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.ThrowableSpell;
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; 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.item.UItems;
import com.minelittlepony.unicopia.util.RegistryUtils; import com.minelittlepony.unicopia.util.RegistryUtils;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
@ -38,48 +34,47 @@ import net.minecraft.server.command.ServerCommandSource;
public final class SpellType<T extends Spell> implements Affine, SpellPredicate<T> { public final class SpellType<T extends Spell> implements Affine, SpellPredicate<T> {
public static final Identifier EMPTY_ID = Unicopia.id("none"); 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<SpellType<?>> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells")); public static final Registry<SpellType<?>> REGISTRY = RegistryUtils.createSimple(Unicopia.id("spells"));
public static final RegistryKey<? extends Registry<SpellType<?>>> REGISTRY_KEY = REGISTRY.getKey(); public static final RegistryKey<? extends Registry<SpellType<?>>> REGISTRY_KEY = REGISTRY.getKey();
public static final Map<Affinity, Set<SpellType<?>>> BY_AFFINITY = new EnumMap<>(Affinity.class);
private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id)); private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id));
public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, PlaceableSpell::new); public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, PlaceableSpell::new);
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, ThrowableSpell::new); public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, GemstoneItem.Shape.DONUT, SpellTraits.EMPTY, ThrowableSpell::new);
public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new); public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, DispersableDisguiseSpell::new);
public static final SpellType<ChangelingFeedingSpell> FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, SpellTraits.EMPTY, ChangelingFeedingSpell::new); public static final SpellType<ChangelingFeedingSpell> FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, ChangelingFeedingSpell::new);
public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new); public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, RainboomAbilitySpell::new);
public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new); public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.FLAME, SpellTraits.EMPTY, RageAbilitySpell::new);
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new); public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, GemstoneItem.Shape.STAR, SpellTraits.EMPTY, TimeControlAbilitySpell::new);
public static final SpellType<IceSpell> FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, IceSpell.DEFAULT_TRAITS, IceSpell::new); public static final SpellType<IceSpell> FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, GemstoneItem.Shape.TRIANGLE, IceSpell.DEFAULT_TRAITS, IceSpell::new);
public static final SpellType<ChillingBreathSpell> CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new); public static final SpellType<ChillingBreathSpell> CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, GemstoneItem.Shape.TRIANGLE, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new);
public static final SpellType<ScorchSpell> SCORCH = register("scorch", Affinity.BAD, 0xF8EC1F, true, ScorchSpell.DEFAULT_TRAITS, ScorchSpell::new); public static final SpellType<ScorchSpell> SCORCH = register("scorch", Affinity.BAD, 0xF8EC1F, true, GemstoneItem.Shape.FLAME, ScorchSpell.DEFAULT_TRAITS, ScorchSpell::new);
public static final SpellType<FireSpell> FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, FireSpell.DEFAULT_TRAITS, FireSpell::new); public static final SpellType<FireSpell> FLAME = register("flame", Affinity.GOOD, 0xFFBB99, true, GemstoneItem.Shape.FLAME, FireSpell.DEFAULT_TRAITS, FireSpell::new);
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new); public static final SpellType<InfernoSpell> INFERNAL = register("infernal", Affinity.BAD, 0xFFAA00, true, GemstoneItem.Shape.FLAME, InfernoSpell.DEFAULT_TRAITS, InfernoSpell::new);
public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new); public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, GemstoneItem.Shape.SHIELD, ShieldSpell.DEFAULT_TRAITS, ShieldSpell::new);
public static final SpellType<AreaProtectionSpell> ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new); public static final SpellType<AreaProtectionSpell> ARCANE_PROTECTION = register("arcane_protection", Affinity.BAD, 0x99CDAA, true, GemstoneItem.Shape.SHIELD, AreaProtectionSpell.DEFAULT_TRAITS, AreaProtectionSpell::new);
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new); public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0xFFEA88, true, GemstoneItem.Shape.VORTEX, AttractiveSpell.DEFAULT_TRAITS, AttractiveSpell::new);
public static final SpellType<DarkVortexSpell> DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new); public static final SpellType<DarkVortexSpell> DARK_VORTEX = register("dark_vortex", Affinity.BAD, 0xA33333, true, GemstoneItem.Shape.VORTEX, DarkVortexSpell.DEFAULT_TRAITS, DarkVortexSpell::new);
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, SpellTraits.EMPTY, NecromancySpell::new); public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0xFA3A3A, true, GemstoneItem.Shape.SKULL, SpellTraits.EMPTY, NecromancySpell::new);
public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, SpellTraits.EMPTY, SiphoningSpell::new); public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xFFA3AA, true, GemstoneItem.Shape.LAMBDA, SpellTraits.EMPTY, SiphoningSpell::new);
public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, SpellTraits.EMPTY, DisperseIllusionSpell::new); public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", Affinity.GOOD, 0xFFFFAF, true, GemstoneItem.Shape.CROSS, SpellTraits.EMPTY, DisperseIllusionSpell::new);
public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, SpellTraits.EMPTY, AwkwardSpell::new); public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.GOOD, 0x3A59FF, true, GemstoneItem.Shape.ICE, SpellTraits.EMPTY, AwkwardSpell::new);
public static final SpellType<TransformationSpell> TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, SpellTraits.EMPTY, TransformationSpell::new); public static final SpellType<TransformationSpell> TRANSFORMATION = register("transformation", Affinity.GOOD, 0x19E48E, true, GemstoneItem.Shape.BRUSH, SpellTraits.EMPTY, TransformationSpell::new);
public static final SpellType<FeatherFallSpell> FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new); public static final SpellType<FeatherFallSpell> FEATHER_FALL = register("feather_fall", Affinity.GOOD, 0x00EEFF, true, GemstoneItem.Shape.LAMBDA, FeatherFallSpell.DEFAULT_TRAITS, FeatherFallSpell::new);
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new); public static final SpellType<CatapultSpell> CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, GemstoneItem.Shape.ROCKET, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new);
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new); public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, GemstoneItem.Shape.FLAME, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new);
public static final SpellType<LightSpell> LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, LightSpell.DEFAULT_TRAITS, LightSpell::new); public static final SpellType<LightSpell> LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, GemstoneItem.Shape.STAR, LightSpell.DEFAULT_TRAITS, LightSpell::new);
public static final SpellType<DisplacementSpell> DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new); public static final SpellType<DisplacementSpell> DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, GemstoneItem.Shape.BRUSH, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new);
public static final SpellType<PortalSpell> PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, PortalSpell.DEFAULT_TRAITS, PortalSpell::new); public static final SpellType<PortalSpell> PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, GemstoneItem.Shape.RING, PortalSpell.DEFAULT_TRAITS, PortalSpell::new);
public static final SpellType<MimicSpell> MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, SpellTraits.EMPTY, MimicSpell::new); public static final SpellType<MimicSpell> MIMIC = register("mimic", Affinity.GOOD, 0xFFFF00, true, GemstoneItem.Shape.ARROW, SpellTraits.EMPTY, MimicSpell::new);
public static final SpellType<MindSwapSpell> MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, SpellTraits.EMPTY, MindSwapSpell::new); public static final SpellType<MindSwapSpell> MIND_SWAP = register("mind_swap", Affinity.BAD, 0xF9FF99, true, GemstoneItem.Shape.WAVE, SpellTraits.EMPTY, MindSwapSpell::new);
public static final SpellType<HydrophobicSpell> HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER)); public static final SpellType<HydrophobicSpell> HYDROPHOBIC = register("hydrophobic", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.ROCKET, SpellTraits.EMPTY, s -> new HydrophobicSpell(s, FluidTags.WATER));
public static final SpellType<BubbleSpell> BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new); public static final SpellType<BubbleSpell> BUBBLE = register("bubble", Affinity.NEUTRAL, 0xF999FF, true, GemstoneItem.Shape.DONUT, BubbleSpell.DEFAULT_TRAITS, BubbleSpell::new);
public static final SpellType<DispellEvilSpell> DISPEL_EVIL = register("dispel_evil", Affinity.GOOD, 0x00FF00, true, DispellEvilSpell.DEFAULT_TRAITS, DispellEvilSpell::new); public static final SpellType<DispellEvilSpell> DISPEL_EVIL = register("dispel_evil", Affinity.GOOD, 0x00FF00, true, GemstoneItem.Shape.CROSS, DispellEvilSpell.DEFAULT_TRAITS, DispellEvilSpell::new);
public static void bootstrap() {} public static void bootstrap() {}
@ -87,6 +82,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
private final Affinity affinity; private final Affinity affinity;
private final int color; private final int color;
private final boolean obtainable; private final boolean obtainable;
private final GemstoneItem.Shape shape;
private final Factory<T> factory; private final Factory<T> factory;
@ -98,11 +94,12 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
private final ItemStack defaultStack; private final ItemStack defaultStack;
private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) { private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory<T> factory) {
this.id = id; this.id = id;
this.affinity = affinity; this.affinity = affinity;
this.color = color; this.color = color;
this.obtainable = obtainable; this.obtainable = obtainable;
this.shape = shape;
this.factory = factory; this.factory = factory;
this.traits = traits; this.traits = traits;
traited = new CustomisedSpellType<>(this, traits); traited = new CustomisedSpellType<>(this, traits);
@ -133,6 +130,10 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return affinity; return affinity;
} }
public GemstoneItem.Shape getGemShape() {
return shape;
}
public SpellTraits getTraits() { public SpellTraits getTraits() {
return traits; return traits;
} }
@ -178,15 +179,12 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return "SpellType[" + getTranslationKey() + "]"; return "SpellType[" + getTranslationKey() + "]";
} }
public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) { public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory<T> factory) {
return register(Unicopia.id(name), affinity, color, obtainable, traits, factory); return register(Unicopia.id(name), affinity, color, obtainable, shape, traits, factory);
} }
public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) { public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, GemstoneItem.Shape shape, SpellTraits traits, Factory<T> factory) {
SpellType<T> type = new SpellType<>(id, affinity, color, obtainable, traits, factory); return Registry.register(REGISTRY, id, new SpellType<>(id, affinity, color, obtainable, shape, traits, factory));
byAffinity(affinity).add(type);
Registry.register(REGISTRY, id, type);
return type;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -203,10 +201,6 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return (SpellType<T>)REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY); return (SpellType<T>)REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY);
} }
public static Set<SpellType<?>> byAffinity(Affinity affinity) {
return BY_AFFINITY.computeIfAbsent(affinity, a -> new LinkedHashSet<>());
}
public static SpellType<?> fromArgument(CommandContext<ServerCommandSource> context, String name) throws CommandSyntaxException { public static SpellType<?> fromArgument(CommandContext<ServerCommandSource> context, String name) throws CommandSyntaxException {
Identifier id = context.getArgument(name, RegistryKey.class).getValue(); Identifier id = context.getArgument(name, RegistryKey.class).getValue();
return REGISTRY.getOrEmpty(id).orElseThrow(() -> UNKNOWN_SPELL_TYPE_EXCEPTION.create(id)); return REGISTRY.getOrEmpty(id).orElseThrow(() -> UNKNOWN_SPELL_TYPE_EXCEPTION.create(id));

View file

@ -18,7 +18,9 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.KeyBinding; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.option.StickyKeyBinding;
import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.client.util.InputUtil;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper; 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 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 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<KeyBinding> pressed = new HashSet<>(); private final Set<KeyBinding> pressed = new HashSet<>();
public KeyBindingsHandler() { public KeyBindingsHandler() {
@ -47,8 +53,12 @@ public class KeyBindingsHandler {
return reverse.get(slot); return reverse.get(slot);
} }
public boolean isToggleMode() {
return Unicopia.getConfig().toggleAbilityKeys.get();
}
public void addKeybind(int code, AbilitySlot slot) { 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); reverse.put(slot, binding);
keys.put(binding, slot); keys.put(binding, slot);
} }
@ -104,6 +114,7 @@ public class KeyBindingsHandler {
int page = Unicopia.getConfig().hudPage.get(); int page = Unicopia.getConfig().hudPage.get();
page += sigma; page += sigma;
Unicopia.getConfig().hudPage.set(page); Unicopia.getConfig().hudPage.set(page);
Unicopia.getConfig().save();
client.getSoundManager().play(PositionedSoundInstance.master(USounds.Vanilla.UI_BUTTON_CLICK, 1.75F + (0.25F * sigma))); 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)); UHud.INSTANCE.setMessage(Text.translatable("gui.unicopia.page_num", page + 1, max + 1));
} }
@ -141,6 +152,27 @@ public class KeyBindingsHandler {
} }
public ActivationType getType() { 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(); long now = System.currentTimeMillis();
if (type != ActivationType.NONE && now > nextPhaseTime - 70) { if (type != ActivationType.NONE && now > nextPhaseTime - 70) {
ActivationType t = type; ActivationType t = type;

View file

@ -122,7 +122,8 @@ public interface URenderers {
register(URenderers::renderBedItem, UItems.CLOTH_BED, UItems.CLOUD_BED); register(URenderers::renderBedItem, UItems.CLOTH_BED, UItems.CLOUD_BED);
register(URenderers::renderChestItem, UBlocks.CLOUD_CHEST.asItem()); 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); 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.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(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() { ModelPredicateProviderRegistry.register(Unicopia.id("zap_cycle"), new ClampedModelPredicateProvider() {

View file

@ -68,6 +68,10 @@ public class SettingsScreen extends GameGui {
}) })
.getStyle().setText("unicopia.options.ignore_mine_lp"); .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()); mineLpStatus = content.addButton(new Label(LEFT, row += 10)).getStyle().setText(getMineLPStatus());
RegistryIndexer<Race> races = RegistryIndexer.of(Race.REGISTRY); RegistryIndexer<Race> races = RegistryIndexer.of(Race.REGISTRY);

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.client.gui; package com.minelittlepony.unicopia.client.gui;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.AbilitySlot;
import com.minelittlepony.unicopia.client.KeyBindingsHandler; import com.minelittlepony.unicopia.client.KeyBindingsHandler;
@ -82,6 +83,12 @@ class Slot {
bSwap &= abilities.isFilled(bSlot); 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.setShaderColor(1, 1, 1, 1);
RenderSystem.enableBlend(); RenderSystem.enableBlend();
MatrixStack matrices = context.getMatrices(); MatrixStack matrices = context.getMatrices();
@ -91,7 +98,7 @@ class Slot {
// background // background
context.drawTexture(UHud.HUD_TEXTURE, 0, 0, backgroundU, backgroundV, size, size, 128, 128); 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 iconPosition = ((size - iconSize + slotPadding + 1) / 2);
int sz = iconSize - slotPadding; int sz = iconSize - slotPadding;
@ -122,6 +129,11 @@ class Slot {
} }
void renderLabel(DrawContext context, AbilityDispatcher abilities, float tickDelta) { 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(); Text label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel();
MatrixStack matrices = context.getMatrices(); MatrixStack matrices = context.getMatrices();

View file

@ -48,8 +48,8 @@ public class UHud {
private final List<Slot> slots = List.of( private final List<Slot> slots = List.of(
new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0), new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0),
new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 26, -5), new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -8),
new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 36, 19) new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 40, 18)
); );
@Nullable @Nullable
@ -68,10 +68,6 @@ public class UHud {
private SpellType<?> focusedType = SpellType.empty(); private SpellType<?> focusedType = SpellType.empty();
public void render(InGameHud hud, DrawContext context, float tickDelta) { 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; final int hotbarZ = -90;
if (client.player == null) { if (client.player == null) {
@ -96,7 +92,6 @@ public class UHud {
font = client.textRenderer; font = client.textRenderer;
xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1; xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1;
matrices.push(); matrices.push();
matrices.translate(scaledWidth / 2, scaledHeight / 2, 0); matrices.translate(scaledWidth / 2, scaledHeight / 2, 0);
@ -109,7 +104,7 @@ public class UHud {
matrices.pop(); matrices.pop();
matrices.push(); matrices.push();
int hudX = ((scaledWidth - 50) / 2) + (104 * xDirection); int hudX = ((scaledWidth - 50) / 2) + (109 * xDirection);
int hudY = scaledHeight - 50; int hudY = scaledHeight - 50;
int hudZ = hotbarZ; int hudZ = hotbarZ;
@ -139,14 +134,13 @@ public class UHud {
slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta));
boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace()) || Abilities.KIRIN_CAST.canUse(pony.getCompositeRace());
if (canCast) {
Ability<?> ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) Ability<?> ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY)
.getAbility(Unicopia.getConfig().hudPage.get()) .getAbility(Unicopia.getConfig().hudPage.get())
.orElse(null); .orElse(null);
boolean canCast = ability == Abilities.CAST || ability == Abilities.KIRIN_CAST || ability == Abilities.SHOOT;
if (ability == Abilities.CAST || ability == Abilities.SHOOT) { if (canCast) {
matrices.push(); matrices.push();
matrices.translate(PRIMARY_SLOT_SIZE / 2F, PRIMARY_SLOT_SIZE / 2F, 0); matrices.translate(PRIMARY_SLOT_SIZE / 2F, PRIMARY_SLOT_SIZE / 2F, 0);
boolean first = !pony.asEntity().isSneaking(); boolean first = !pony.asEntity().isSneaking();
@ -158,7 +152,9 @@ public class UHud {
prevReplacing = replacing; prevReplacing = replacing;
setMessage(ability.getName(pony)); setMessage(ability.getName(pony));
} }
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(first ? 37 : 63)); 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.translate(-23, 0, 0);
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-26)); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-26));
matrices.scale(0.8F, 0.8F, 1); matrices.scale(0.8F, 0.8F, 1);
@ -166,15 +162,19 @@ public class UHud {
context.drawTexture(HUD_TEXTURE, 0, 0, u, 120, 13, 7, 128, 128); context.drawTexture(HUD_TEXTURE, 0, 0, u, 120, 13, 7, 128, 128);
matrices.pop(); matrices.pop();
} }
}
slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta)); slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta));
matrices.pop(); matrices.pop();
if (canCast) { 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.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); SpellIconRenderer.renderSpell(context, pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 8 - xDirection * 2, hudY - 6, EQUIPPED_GEMSTONE_SCALE);
matrices.pop();
} }
RenderSystem.disableBlend(); RenderSystem.disableBlend();
@ -198,7 +198,7 @@ public class UHud {
float vortexDistortion = DarkVortexSpellRenderer.getCameraDistortion(); float vortexDistortion = DarkVortexSpellRenderer.getCameraDistortion();
if (vortexDistortion > 20) { if (vortexDistortion > 25) {
context.fill(RenderLayers.getEndPortal(), 0, 0, scaledWidth, scaledHeight, 0); context.fill(RenderLayers.getEndPortal(), 0, 0, scaledWidth, scaledHeight, 0);
context.getMatrices().push(); context.getMatrices().push();
context.getMatrices().translate(scaledWidth / 2, scaledHeight / 2, 0); context.getMatrices().translate(scaledWidth / 2, scaledHeight / 2, 0);
@ -206,7 +206,7 @@ public class UHud {
context.getMatrices().pop(); context.getMatrices().pop();
return; return;
} else if (vortexDistortion > 0) { } 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); boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS);

View file

@ -50,7 +50,7 @@ class BodyPartGear<M extends ClientPonyModel<LivingEntity>> implements Gear {
public static final Predicate<LivingEntity> UNICORN_HORN_PREDICATE = MINE_LP_HAS_NO_HORN.and(AmuletSelectors.ALICORN_AMULET.or(EquinePredicates.raceMatches(com.minelittlepony.unicopia.Race::canCast))); public static final Predicate<LivingEntity> 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 Identifier UNICORN_HORN = Unicopia.id("textures/models/horn/unicorn.png");
public static final Predicate<LivingEntity> PEGA_WINGS_PREDICATE = MINE_LP_HAS_NO_WINGS.and(AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(race -> race.flightType() == FlightType.AVIAN))); public static final Predicate<LivingEntity> 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 final Identifier PEGASUS_WINGS = Unicopia.id("textures/models/wings/pegasus_pony.png");
public static BodyPartGear<WingsGearModel> pegasusWings() { public static BodyPartGear<WingsGearModel> pegasusWings() {

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.model.Dilation; import net.minecraft.client.model.Dilation;
@ -56,7 +57,9 @@ public class BatWingsFeatureRenderer<E extends LivingEntity> extends WingsFeatur
@Override @Override
protected boolean canRender(E entity) { 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 @Override

View file

@ -1,7 +1,9 @@
package com.minelittlepony.unicopia.client.render; package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.FlightType;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.model.Dilation; import net.minecraft.client.model.Dilation;
@ -51,7 +53,10 @@ public class WingsFeatureRenderer<E extends LivingEntity> implements AccessoryFe
} }
protected boolean canRender(E entity) { 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) { protected Identifier getTexture(E entity) {

View file

@ -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.RenderLayers;
import com.minelittlepony.unicopia.client.render.model.PlaneModel; import com.minelittlepony.unicopia.client.render.model.PlaneModel;
import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.client.render.model.SphereModel;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
public class DarkVortexSpellRenderer extends SpellRenderer<DarkVortexSpell> { public class DarkVortexSpellRenderer extends SpellRenderer<DarkVortexSpell> {
@ -36,65 +38,72 @@ public class DarkVortexSpellRenderer extends SpellRenderer<DarkVortexSpell> {
@Override @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) { 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 radius = (float)spell.getEventHorizonRadius();
float absDistance = (float)cameraEntity.getEyePos().distanceTo(caster.getOriginVector().add(0, 2, 0));
float absDistance = (float)ray.length();
matrices.push(); 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.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 + 7), 0.0000001F, 1);
float distance = 1F / MathHelper.clamp((absDistance / (radius * 4)), 0.0000001F, 1);
distance *= distance; distance *= distance;
if (absDistance < radius * 4) { if (absDistance < radius * 4) {
cameraDistortion += distance; cameraDistortion += distance;
} }
matrices.scale(distance, distance, distance); SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getEndPortal()), light, 1, radius * 0.5F, 0, 0, 0, 0);
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);
if (radius > 0.3F && absDistance > radius) { 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); radius *= Math.min(2, 3 + radius);
matrices.scale(radius, radius, radius); float processionSpeed = animationProgress * 0.02F;
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); float maxProcessionAngle = 15;
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(animationProgress * 168));
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)); VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(ACCRETION_DISK_TEXTURE));
PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1);
float secondaryScale = 0.9F + cosProcession * 0.3F;
matrices.push(); matrices.translate(0, 0, 0.0001F);
matrices.scale(0.5F, 0.5F, 0.5F); matrices.scale(secondaryScale, secondaryScale, secondaryScale);
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33)); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33));
PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1);
matrices.pop(); matrices.translate(0, 0, 0.0001F);
matrices.scale(0.9F, 0.9F, 0.9F);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(45)); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33));
PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1);
} }
matrices.pop(); matrices.pop();

View file

@ -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.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.Living; 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.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer.TextLayerType; import net.minecraft.client.font.TextRenderer.TextLayerType;
@ -91,6 +94,9 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
if (client.getEntityRenderDispatcher().shouldRenderHitboxes() if (client.getEntityRenderDispatcher().shouldRenderHitboxes()
&& !client.hasReducedDebugInfo() && !client.hasReducedDebugInfo()
&& !(caster.asEntity() == client.cameraEntity && client.options.getPerspective() == Perspective.FIRST_PERSON)) { && !(caster.asEntity() == client.cameraEntity && client.options.getPerspective() == Perspective.FIRST_PERSON)) {
if (!(caster instanceof Pony || caster instanceof CastSpellEntity)) {
return;
}
renderHotspot(matrices, vertices, caster, animationProgress); renderHotspot(matrices, vertices, caster, animationProgress);
renderSpellDebugInfo(matrices, vertices, caster, light); renderSpellDebugInfo(matrices, vertices, caster, light);
} }

View file

@ -21,7 +21,7 @@ import net.minecraft.util.Identifier;
public class UCommandSuggestion { public class UCommandSuggestion {
public static final SuggestionProvider<ServerCommandSource> ALL_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY); public static final SuggestionProvider<ServerCommandSource> ALL_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY);
public static final SuggestionProvider<ServerCommandSource> ALLOWED_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY, (context, race) -> race.isPermitted(context.getSource().getPlayer())); public static final SuggestionProvider<ServerCommandSource> ALLOWED_RACE_SUGGESTIONS = suggestFromRegistry(Race.REGISTRY_KEY, (context, race) -> race.availability().isGrantable() && race.isPermitted(context.getSource().getPlayer()));
public static <T> SuggestionProvider<ServerCommandSource> suggestFromRegistry(RegistryKey<? extends Registry<T>> registryKey, @Nullable BiPredicate<CommandContext<ServerCommandSource>, T> filter) { public static <T> SuggestionProvider<ServerCommandSource> suggestFromRegistry(RegistryKey<? extends Registry<T>> registryKey, @Nullable BiPredicate<CommandContext<ServerCommandSource>, T> filter) {
return (context, builder) -> { return (context, builder) -> {
@ -43,7 +43,7 @@ public class UCommandSuggestion {
} }
public static <T> void forEachMatching(Iterable<T> candidates, String input, Function<T, Identifier> idFunc, Consumer<T> consumer, String defaultNamespace) { public static <T> void forEachMatching(Iterable<T> candidates, String input, Function<T, Identifier> idFunc, Consumer<T> consumer, String defaultNamespace) {
final boolean hasNamespaceDelimiter = input.indexOf(58) > -1; final boolean hasNamespaceDelimiter = input.indexOf(':') > -1;
for (T object : candidates) { for (T object : candidates) {
final Identifier id = idFunc.apply(object); final Identifier id = idFunc.apply(object);
if (hasNamespaceDelimiter) { if (hasNamespaceDelimiter) {

View file

@ -28,6 +28,13 @@ public final class ModelOverrides {
this.model = model; this.model = model;
} }
public <T> ModelOverrides addUniform(String key, Iterable<T> values, Function<T, Float> idFunc, Function<T, Identifier> 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) { public ModelOverrides addUniform(String key, int from, int to, Identifier model) {
float step = 1F / to; float step = 1F / to;
for (int index = from; index <= to; index++) { for (int index = from; index <= to; index++) {

View file

@ -1,12 +1,14 @@
package com.minelittlepony.unicopia.datagen.providers; package com.minelittlepony.unicopia.datagen.providers;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.DataCollector; import com.minelittlepony.unicopia.datagen.DataCollector;
import com.minelittlepony.unicopia.item.BedsheetsItem; import com.minelittlepony.unicopia.item.BedsheetsItem;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider; import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
@ -137,8 +139,7 @@ public class UModelProvider extends FabricModelProvider {
// gemstone // gemstone
ModelOverrides.of(ItemModels.GENERATED) ModelOverrides.of(ItemModels.GENERATED)
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_pure"), "affinity", 0) .addUniform("shape", List.of(GemstoneItem.Shape.values()), GemstoneItem.Shape::getId, shape -> ModelIds.getItemSubModelId(UItems.GEMSTONE, "_" + shape.name().toLowerCase(Locale.ROOT)))
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_corrupted"), "affinity", 1)
.upload(UItems.GEMSTONE, itemModelGenerator); .upload(UItems.GEMSTONE, itemModelGenerator);
// fishing rod // fishing rod

View file

@ -44,7 +44,11 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
UBlocks.GOLDEN_OAK_SPROUT 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.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(UTags.Blocks.JARS).add(UBlocks.JAR, UBlocks.CLOUD_JAR, UBlocks.STORM_JAR, UBlocks.LIGHTNING_JAR, UBlocks.ZAP_JAR);
getOrCreateTagBuilder(BlockTags.CROPS).add(crops); getOrCreateTagBuilder(BlockTags.CROPS).add(crops);

View file

@ -22,7 +22,7 @@ import net.minecraft.world.World;
/** /**
* An indirect reference to an entity by its unique id. * 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. * remember who they belong to even when the entity has been unloaded.
* *
* Will also remember the position and certain attributes of the owner. * Will also remember the position and certain attributes of the owner.

View file

@ -11,7 +11,6 @@ import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.item.ButterflyItem; import com.minelittlepony.unicopia.item.ButterflyItem;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -74,7 +73,7 @@ public class ButterflyEntity extends AmbientEntity {
} }
public static boolean canSpawn(EntityType<? extends ButterflyEntity> type, WorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) { public static boolean canSpawn(EntityType<? extends ButterflyEntity> 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 @Override

View file

@ -26,7 +26,8 @@ import net.minecraft.world.Heightmap.Type;
public interface UEntities { public interface UEntities {
EntityType<ButterflyEntity> BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.AMBIENT).entityFactory(ButterflyEntity::new) EntityType<ButterflyEntity> 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))); .dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
EntityType<MagicProjectileEntity> THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new) EntityType<MagicProjectileEntity> THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new)
.trackRangeBlocks(100) .trackRangeBlocks(100)
@ -83,7 +84,7 @@ public interface UEntities {
.trackRangeChunks(8) .trackRangeChunks(8)
.dimensions(EntityDimensions.fixed(3, 2))); .dimensions(EntityDimensions.fixed(3, 2)));
EntityType<SpecterEntity> SPECTER = register("specter", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.MONSTER).entityFactory(SpecterEntity::new) EntityType<SpecterEntity> 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() .fireImmune()
.spawnableFarFromPlayer() .spawnableFarFromPlayer()
.dimensions(EntityDimensions.fixed(1, 2))); .dimensions(EntityDimensions.fixed(1, 2)));

View file

@ -1,7 +1,10 @@
package com.minelittlepony.unicopia.entity.player; package com.minelittlepony.unicopia.entity.player;
import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; 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.entity.damage.DamageSource;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
@ -82,7 +84,9 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private int wallHitCooldown; private int wallHitCooldown;
private Vec3d lastPos = Vec3d.ZERO; @Nullable
private DimensionType lastDimension;
private Optional<Vec3d> lastPos = Optional.empty();
private Vec3d lastVel = Vec3d.ZERO; private Vec3d lastVel = Vec3d.ZERO;
private final PlayerDimensions dimensions; private final PlayerDimensions dimensions;
@ -248,8 +252,14 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
ticksToGlide--; ticksToGlide--;
} }
lastVel = entity.getPos().subtract(lastPos); DimensionType dimension = entity.getWorld().getDimension();
lastPos = entity.getPos(); 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()); final MutableVector velocity = new MutableVector(entity.getVelocity());
@ -547,7 +557,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private void checkAvianTakeoffConditions(MutableVector velocity) { private void checkAvianTakeoffConditions(MutableVector velocity) {
double horMotion = getHorizontalMotion(); double horMotion = getHorizontalMotion();
double motion = entity.getPos().subtract(lastPos).lengthSquared(); double motion = lastVel.lengthSquared();
boolean takeOffCondition = boolean takeOffCondition =
(horMotion > 0.05 || motion > 0.05) (horMotion > 0.05 || motion > 0.05)
@ -581,10 +591,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
entity.calculateDimensions(); entity.calculateDimensions();
if (entity.isOnGround() || !force) { if (entity.isOnGround() || !force) {
BlockState steppingState = pony.asEntity().getSteppingBlockState(); //BlockState steppingState = pony.asEntity().getSteppingBlockState();
if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) { /*if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) {
pony.addParticle(new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), pony.getOrigin().toCenterPos(), Vec3d.ZERO); pony.addParticle(new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), pony.getOrigin().toCenterPos(), Vec3d.ZERO);
} else { } else*/ {
Supplier<Vec3d> pos = VecHelper.sphere(pony.asWorld().getRandom(), 0.5D); Supplier<Vec3d> pos = VecHelper.sphere(pony.asWorld().getRandom(), 0.5D);
Supplier<Vec3d> vel = VecHelper.sphere(pony.asWorld().getRandom(), 0.015D); Supplier<Vec3d> vel = VecHelper.sphere(pony.asWorld().getRandom(), 0.015D);
pony.spawnParticles(ParticleTypes.CLOUD, pos, vel, 5); pony.spawnParticles(ParticleTypes.CLOUD, pos, vel, 5);
@ -716,7 +726,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
} }
private void applyTurbulance(MutableVector velocity) { 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); float effectStrength = Math.min(1, (float)ticksInAir / MAX_TICKS_TO_WEATHER_EFFECTS) * (globalEffectStrength / 100F);
Vec3d gust = WeatherConditions.getGustStrength(entity.getWorld(), entity.getBlockPos()) Vec3d gust = WeatherConditions.getGustStrength(entity.getWorld(), entity.getBlockPos())
.multiply(globalEffectStrength / 100D) .multiply(globalEffectStrength / 100D)

View file

@ -535,15 +535,17 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
return; return;
} }
if (animationDuration > 0 && --animationDuration <= 0) { if (animationDuration <= 0 || --animationDuration <= 0) {
if (animation.renderBothArms() && acrobatics.distanceClimbed > 0) { if (animation.renderBothArms() && acrobatics.distanceClimbed > 0) {
return; return;
} }
if (!getAnimation().isOf(Animation.NONE)) {
setAnimation(AnimationInstance.NONE); setAnimation(AnimationInstance.NONE);
} }
} }
}
private void updateBatPonyAbilities() { private void updateBatPonyAbilities() {
if (ticksSunImmunity > 0) { if (ticksSunImmunity > 0) {

View file

@ -4,8 +4,10 @@ import java.util.Optional;
import net.minecraft.advancement.criterion.Criteria; import net.minecraft.advancement.criterion.Criteria;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsage;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.stat.Stats; import net.minecraft.stat.Stats;
import net.minecraft.util.UseAction; import net.minecraft.util.UseAction;
@ -29,9 +31,18 @@ public class ConsumableItem extends Item {
serverPlayerEntity.incrementStat(Stats.USED.getOrCreateStat(this)); serverPlayerEntity.incrementStat(Stats.USED.getOrCreateStat(this));
} }
if (stack.isEmpty()) {
return stack.isEmpty() ? Optional.ofNullable(getRecipeRemainder()).map(Item::getDefaultStack).orElse(ItemStack.EMPTY) : stack; 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 @Override
public UseAction getUseAction(ItemStack stack) { public UseAction getUseAction(ItemStack stack) {
return action; return action;

View file

@ -1,12 +1,10 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import java.util.Arrays; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
@ -96,11 +94,12 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem {
@Override @Override
public List<ItemStack> getDefaultStacks() { public List<ItemStack> getDefaultStacks() {
return Arrays.stream(Affinity.VALUES) return SpellType.REGISTRY.stream()
.flatMap(i -> SpellType.byAffinity(i).stream() .filter(SpellType::isObtainable)
.filter(type -> type.isObtainable()) .sorted(
.map(type -> EnchantableItem.enchant(getDefaultStack(), type, i)) Comparator.<SpellType<?>, GemstoneItem.Shape>comparing(SpellType::getGemShape).thenComparing(Comparator.comparing(SpellType::getAffinity))
) )
.map(type -> EnchantableItem.enchant(getDefaultStack(), type))
.toList(); .toList();
} }
@ -121,4 +120,29 @@ public class GemstoneItem extends Item implements MultiItem, EnchantableItem {
return super.getName(); 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;
}
}
} }

View file

@ -111,7 +111,7 @@ public interface UItems {
Item TOM = register("tom", new BluntWeaponItem(new Item.Settings(), ImmutableMultimap.of( 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) EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, new EntityAttributeModifier(BluntWeaponItem.KNOCKBACK_MODIFIER_ID, "Weapon modifier", 0.9, EntityAttributeModifier.Operation.ADDITION)
)), ItemGroups.NATURAL); )), 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 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); 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_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 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 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); Item CARAPACE = register("carapace", new Item(new Item.Settings()), ItemGroups.INGREDIENTS);

View file

@ -211,7 +211,7 @@ public class Ether extends PersistentState {
} }
public boolean isAvailable() { public boolean isAvailable() {
return !isDead() && !taken; return !isDead() && !taken && entity.isSet();
} }
public void setTaken(boolean taken) { public void setTaken(boolean taken) {
@ -219,6 +219,18 @@ public class Ether extends PersistentState {
markDirty(); markDirty();
} }
public void release() {
setTaken(false);
}
public boolean claim() {
if (isAvailable()) {
setTaken(true);
return true;
}
return false;
}
@Nullable @Nullable
public T getSpell() { public T getSpell() {
if (removed) { if (removed) {

View file

@ -1,15 +1,18 @@
package com.minelittlepony.unicopia.server.world; 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;
import net.minecraft.world.GameRules.BooleanRule; import net.minecraft.world.GameRules.BooleanRule;
import net.minecraft.world.GameRules.IntRule; import net.minecraft.world.GameRules.IntRule;
public interface UGameRules { public interface UGameRules {
GameRules.Key<BooleanRule> SWAP_TRIBE_ON_DEATH = GameRules.register("swapTribeOnDeath", GameRules.Category.SPAWNING, BooleanRule.create(false)); GameRules.Key<BooleanRule> SWAP_TRIBE_ON_DEATH = GameRuleRegistry.register("swapTribeOnDeath", GameRules.Category.SPAWNING, GameRuleFactory.createBooleanRule(false));
GameRules.Key<BooleanRule> ANNOUNCE_TRIBE_JOINS = GameRules.register("announceTribeJoins", GameRules.Category.SPAWNING, BooleanRule.create(false)); GameRules.Key<BooleanRule> ANNOUNCE_TRIBE_JOINS = GameRuleRegistry.register("announceTribeJoins", GameRules.Category.SPAWNING, GameRuleFactory.createBooleanRule(false));
GameRules.Key<BooleanRule> DO_NOCTURNAL_BAT_PONIES = GameRules.register("doNocturnalBatPonies", GameRules.Category.PLAYER, BooleanRule.create(true)); GameRules.Key<BooleanRule> DO_NOCTURNAL_BAT_PONIES = GameRuleRegistry.register("doNocturnalBatPonies", GameRules.Category.PLAYER, GameRuleFactory.createBooleanRule(true));
GameRules.Key<IntRule> WEATHER_EFFECTS_STRENGTH = GameRules.register("weatherEffectsStrength", GameRules.Category.MISC, IntRule.create(100)); GameRules.Key<IntRule> WEATHER_EFFECTS_STRENGTH = GameRuleRegistry.register("weatherEffectsStrength", GameRules.Category.MISC, GameRuleFactory.createIntRule(100, 0, 100));
GameRules.Key<BooleanRule> DO_TIME_MAGIC = GameRules.register("doTimeMagic", GameRules.Category.PLAYER, BooleanRule.create(true)); GameRules.Key<BooleanRule> DO_TIME_MAGIC = GameRuleRegistry.register("doTimeMagic", GameRules.Category.PLAYER, GameRuleFactory.createBooleanRule(true));
GameRules.Key<IntRule> MAX_DARK_VORTEX_SIZE = GameRuleRegistry.register("maxDarkVortexSize", GameRules.Category.PLAYER, GameRuleFactory.createIntRule(20, 1, 25));
static void bootstrap() { } static void bootstrap() { }
} }

View file

@ -544,7 +544,7 @@
"spell.unicopia.shield.lore": "Casts a protective shield around the user", "spell.unicopia.shield.lore": "Casts a protective shield around the user",
"spell.unicopia.bubble": "Bubble", "spell.unicopia.bubble": "Bubble",
"spell.unicopia.bubble.lore": "Traps any creature it hits in a soap 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.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": "Arcane Attraction",
"spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets", "spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets",
@ -1329,6 +1329,9 @@
"key.unicopia.secondary": "Secondary Ability", "key.unicopia.secondary": "Secondary Ability",
"key.unicopia.tertiary": "Tertiary Ability", "key.unicopia.tertiary": "Tertiary Ability",
"key.unicopia.passive": "Passive 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_dn": "Hud Previous Page",
"key.unicopia.hud_page_up": "Hud Next Page", "key.unicopia.hud_page_up": "Hud Next Page",
@ -1408,6 +1411,7 @@
"commands.gravity.set.multiple": "Updated %s entities", "commands.gravity.set.multiple": "Updated %s entities",
"unicopia.options.title": "Unicopia Options", "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": "Ignore Mine Little Pony",
"unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony is not installed", "unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony is not installed",
"unicopia.options.ignore_mine_lp.detected": "* Your detected race is %s", "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.list": "[Config] Property (%s) contains (%s) entries: ",
"command.unicopia.config.clear": "[Config] Cleared all values from property %s", "command.unicopia.config.clear": "[Config] Cleared all values from property %s",
"unicopia.race.unset": "Unset", "race.unicopia.unset": "Unset",
"unicopia.race.unset.alt": "Unset", "race.unicopia.unset.alt": "Unset",
"unicopia.race.human": "Human", "race.unicopia.human": "Human",
"unicopia.race.human.alt": "Humans", "race.unicopia.human.alt": "Humans",
"unicopia.race.earth": "Earth Pony", "race.unicopia.earth": "Earth Pony",
"unicopia.race.earth.alt": "Earth Ponies", "race.unicopia.earth.alt": "Earth Ponies",
"unicopia.race.unicorn": "Unicorn", "race.unicopia.unicorn": "Unicorn",
"unicopia.race.unicorn.alt": "Unicorns", "race.unicopia.unicorn.alt": "Unicorns",
"unicopia.race.pegasus": "Pegasus", "race.unicopia.pegasus": "Pegasus",
"unicopia.race.pegasus.alt": "Pegasi", "race.unicopia.pegasus.alt": "Pegasi",
"unicopia.race.alicorn": "Alicorn", "race.unicopia.alicorn": "Alicorn",
"unicopia.race.alicorn.alt": "Alicorns", "race.unicopia.alicorn.alt": "Alicorns",
"unicopia.race.changeling": "Changeling", "race.unicopia.changeling": "Changeling",
"unicopia.race.changeling.alt": "Changelings", "race.unicopia.changeling.alt": "Changelings",
"unicopia.race.bat": "Bat Pony", "race.unicopia.bat": "Bat Pony",
"unicopia.race.bat.alt": "Bat Ponies", "race.unicopia.bat.alt": "Bat Ponies",
"unicopia.race.kirin": "Kirin", "race.unicopia.kirin": "Kirin",
"unicopia.race.kirin.alt": "Kirins", "race.unicopia.kirin.alt": "Kirins",
"unicopia.race.hippogriff": "Hippogriff", "race.unicopia.hippogriff": "Hippogriff",
"unicopia.race.hippogriff.alt": "Hippogriffs", "race.unicopia.hippogriff.alt": "Hippogriffs",
"unicopia.race.seapony": "Sea Pony", "race.unicopia.seapony": "Sea Pony",
"unicopia.race.seapony.alt": "Sea Ponies", "race.unicopia.seapony.alt": "Sea Ponies",
"death.attack.unicopia.generic.and_also": "%1$s and %2$s", "death.attack.unicopia.generic.and_also": "%1$s and %2$s",
"death.attack.unicopia.generic.whilst_flying": "%1$s whilst flying", "death.attack.unicopia.generic.whilst_flying": "%1$s whilst flying",

View file

@ -74,6 +74,14 @@
"item.unicopia.cooked_zap_apple": "Печёное зап-яблоко", "item.unicopia.cooked_zap_apple": "Печёное зап-яблоко",
"item.unicopia.zap_apple": "Зап-яблоко", "item.unicopia.zap_apple": "Зап-яблоко",
"item.unicopia.zap_bulb": "Недозрелое зап-яблоко", "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_bottle": "Бутылочка любви",
"item.unicopia.love_bucket": "Ведро любви", "item.unicopia.love_bucket": "Ведро любви",
@ -81,11 +89,16 @@
"item.unicopia.plunder_vine": "Чёрная лоза", "item.unicopia.plunder_vine": "Чёрная лоза",
"item.unicopia.empty_jar": "Стеклянная банка", "item.unicopia.empty_jar": "Стеклянная банка",
"block.unicopia.jar": "Стеклянная банка",
"item.unicopia.filled_jar": "%s в банке", "item.unicopia.filled_jar": "%s в банке",
"item.unicopia.rain_cloud_jar": "Дождь в банке", "item.unicopia.rain_cloud_jar": "Дождь в банке",
"item.unicopia.cloud_jar": "Дождь в банке",
"item.unicopia.storm_cloud_jar": "Буря в банке", "item.unicopia.storm_cloud_jar": "Буря в банке",
"block.unicopia.storm_jar": "Буря в банке",
"item.unicopia.lightning_jar": "Молния в банке", "item.unicopia.lightning_jar": "Молния в банке",
"block.unicopia.lightning_jar": "Молния в банке",
"item.unicopia.zap_apple_jam_jar": "Джем из зап-яблока", "item.unicopia.zap_apple_jam_jar": "Джем из зап-яблока",
"block.unicopia.zap_jar": "Банка зап-яблочного джема",
"item.unicopia.toast": "Тост", "item.unicopia.toast": "Тост",
"item.unicopia.burned_toast": "Подгоревший тост", "item.unicopia.burned_toast": "Подгоревший тост",
@ -145,7 +158,13 @@
"item.unicopia.crispy_hay_fries": "Хрустящий картофель фри", "item.unicopia.crispy_hay_fries": "Хрустящий картофель фри",
"item.unicopia.horse_shoe_fries": "Подкова из картофеля фри", "item.unicopia.horse_shoe_fries": "Подкова из картофеля фри",
"item.unicopia.wheat_worms": "Пшеничные черви", "item.unicopia.wheat_worms": "Пшеничные черви",
"item.unicopia.baited_fishing_rod": "Удочка с приманкой",
"item.unicopia.muffin": "Маффин", "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": "Крылья Икара",
"item.unicopia.pegasus_amulet.lore": "Дарует временный полёт тому, кто носит его", "item.unicopia.pegasus_amulet.lore": "Дарует временный полёт тому, кто носит его",
@ -197,6 +216,7 @@
"item.unicopia.music_disc_funk.desc": "Фанк, просто фанк", "item.unicopia.music_disc_funk.desc": "Фанк, просто фанк",
"item.unicopia.cloud_lump": "Облачный ком", "item.unicopia.cloud_lump": "Облачный ком",
"item.unicopia.white_bed_sheets": "Белая простынь",
"item.unicopia.light_gray_bed_sheets": "Светло-серая простынь", "item.unicopia.light_gray_bed_sheets": "Светло-серая простынь",
"item.unicopia.gray_bed_sheets": "Серая простынь", "item.unicopia.gray_bed_sheets": "Серая простынь",
"item.unicopia.black_bed_sheets": "Черная простынь", "item.unicopia.black_bed_sheets": "Черная простынь",
@ -279,6 +299,7 @@
"block.unicopia.golden_oak_leaves": "Листья золотого дуба", "block.unicopia.golden_oak_leaves": "Листья золотого дуба",
"block.unicopia.golden_oak_log": "Бревно золотого дуба", "block.unicopia.golden_oak_log": "Бревно золотого дуба",
"block.unicopia.mango": "Манго", "block.unicopia.mango": "Манго",
"block.unicopia.worm_block": "Блок червей",
"block.unicopia.mango_leaves": "Листья мангового дерева", "block.unicopia.mango_leaves": "Листья мангового дерева",
"block.unicopia.mango_sapling": "Саженец мангового дерева", "block.unicopia.mango_sapling": "Саженец мангового дерева",
"block.unicopia.potted_mango_sapling": "Саженец манго в горшке", "block.unicopia.potted_mango_sapling": "Саженец манго в горшке",
@ -353,7 +374,8 @@
"block.unicopia.oats_crown": "Овёс", "block.unicopia.oats_crown": "Овёс",
"entity.unicopia.butterfly": "Бабочка", "entity.unicopia.butterfly": "Бабочка",
"entity.unicopia.twittermite": "Твиттермиты", "entity.unicopia.twittermite": "Твиттермит",
"entity.unicopia.specter": "Призрак",
"entity.unicopia.cast_spell": "Заклинание", "entity.unicopia.cast_spell": "Заклинание",
"entity.unicopia.cast_spell.by": "Заклинание, наложенное %s", "entity.unicopia.cast_spell.by": "Заклинание, наложенное %s",
"entity.unicopia.spellbook": "Книга заклинаний", "entity.unicopia.spellbook": "Книга заклинаний",
@ -605,42 +627,43 @@
"unicopia.diet.hunger": "Коэффициент голода: %s%%", "unicopia.diet.hunger": "Коэффициент голода: %s%%",
"unicopia.diet.saturation": "Коэффициент насыщения: %s%%", "unicopia.diet.saturation": "Коэффициент насыщения: %s%%",
"tag.unicopia.food_types.rotten_meat": "Гниющее мясо", "food_group.unicopia.meat.rotten": "Гниющее мясо",
"tag.unicopia.food_types.raw_meat": "Свежее мясо", "food_group.unicopia.meat.raw": "Свежее мясо",
"tag.unicopia.food_types.cooked_meat": "Готовое мясо", "food_group.unicopia.meat.cooked": "Готовое мясо",
"tag.unicopia.food_types.raw_fish": "Свежая рыба", "food_group.unicopia.fish.rotten": "Гнилая рыба",
"tag.unicopia.food_types.cooked_fish": "Готовая рыба", "food_group.unicopia.fish.raw": "Свежая рыба",
"tag.unicopia.food_types.raw_insect": "Жуки и насекомые", "food_group.unicopia.fish.cooked": "Готовая рыба",
"tag.unicopia.food_types.cooked_insect": "Приготовленные жуки и насекомые", "food_group.unicopia.insect.rotten": "Гнилые жуки и насекомые",
"tag.unicopia.food_types.nuts_and_seeds": "Орехи и семена", "food_group.unicopia.insect.raw": "Жуки и насекомые",
"tag.unicopia.food_types.love": "Любовь", "food_group.unicopia.insect.cooked": "Приготовленные жуки и насекомые",
"tag.unicopia.food_types.rocks": "Камни", "food_group.unicopia.nuts_and_seeds": "Орехи и семена",
"tag.unicopia.food_types.pinecone": "Орехи и семена", "food_group.unicopia.love": "Любовь",
"tag.unicopia.food_types.bat_ponys_delight": "Лакомства бэтпони", "food_group.unicopia.rocks": "Камни",
"tag.unicopia.food_types.cooked_sea_vegitables": "Готовая рыбная еда", "food_group.unicopia.pinecone": "Орехи и семена",
"tag.unicopia.food_types.raw_sea_vegitables": "Свежая рыбная еда", "food_group.unicopia.bat_ponys_delight": "Лакомства бэтпони",
"tag.unicopia.food_types.shells": "Морские ракушки", "food_group.unicopia.sea_vegetable.cooked": "Подготовленные ракушки и кораллы",
"tag.unicopia.food_types.shelly": "Морские ракушки", "food_group.unicopia.sea_vegetable.raw": "Ракушки и кораллы",
"tag.unicopia.food_types.candy": "Конфеты", "food_group.unicopia.shells": "Морские ракушки",
"tag.unicopia.food_types.desserts": "Десерты", "food_group.unicopia.special_shells": "Компаньоны",
"tag.unicopia.food_types.fruit": "Фрукты", "food_group.unicopia.candy": "Конфеты",
"tag.unicopia.food_types.baked_goods": "Выпечка", "food_group.unicopia.desserts": "Десерты",
"tag.unicopia.food_types.misc": "Прочее", "food_group.unicopia.fruit": "Фрукты",
"tag.unicopia.food_types.fruits_and_vegetables": "Фрукты и овощи", "food_group.unicopia.baked_goods": "Выпечка",
"tag.unicopia.food_types.drinks": "Напитки", "food_group.unicopia.misc": "Прочее",
"tag.minecraft.leaves": "Листья", "food_group.unicopia.fruits_and_vegetables": "Фрукты и овощи",
"food_group.unicopia.drinks": "Напитки",
"tag.unicopia.food_types.forage_edible_filling": "Крупная растительная масса", "food_group.unicopia.foraging.edible_filling": "Крупная растительная масса",
"tag.unicopia.food_types.forage_edible": "Растительная масса", "food_group.unicopia.foraging.edible": "Растительная масса",
"tag.unicopia.food_types.forage_nauseating": "Тошнотворное", "food_group.unicopia.foraging.nauseating": "Тошнотворное",
"tag.unicopia.food_types.forage_prickly": "Колючее", "food_group.unicopia.foraging.prickly": "Колючее",
"tag.unicopia.food_types.forage_risky": "Небезопасное", "food_group.unicopia.foraging.risky": "Небезопасное",
"tag.unicopia.food_types.forage_strengthening": "Повышающее силу", "food_group.unicopia.foraging.strengthening": "Повышающее силу",
"tag.unicopia.food_types.forage_severely_prickly": "Очень колючее", "food_group.unicopia.foraging.severely_prickly": "Очень колючее",
"tag.unicopia.food_types.forage_severely_nauseating": "Отвратительное", "food_group.unicopia.foraging.severely_nauseating": "Отвратительное",
"tag.unicopia.food_types.forage_radioactive": "Светящееся", "food_group.unicopia.foraging.radioactive": "Светящееся",
"tag.unicopia.food_types.forage_dangerous": "Опасное", "food_group.unicopia.foraging.dangerous": "Опасное",
"tag.unicopia.food_types.forage_blinding": "Токсичное", "food_group.unicopia.foraging.blinding": "Токсичное",
"food_group.unicopia.foraging.leafy_greens": "Листовая зелень",
"toxicity.safe.name": "Безопасное", "toxicity.safe.name": "Безопасное",
"toxicity.mild.name": "Слаботоксичное", "toxicity.mild.name": "Слаботоксичное",
@ -1306,6 +1329,9 @@
"key.unicopia.secondary": "Вторичная способность", "key.unicopia.secondary": "Вторичная способность",
"key.unicopia.tertiary": "Третичная способность", "key.unicopia.tertiary": "Третичная способность",
"key.unicopia.passive": "Пассивная способность", "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_dn": "Предыдущая страница",
"key.unicopia.hud_page_up": "Следующая страница", "key.unicopia.hud_page_up": "Следующая страница",
@ -1332,6 +1358,8 @@
"enchantment.unicopia.heart_bound.desc": "Заставляет предмет оставаться с вами после смерти", "enchantment.unicopia.heart_bound.desc": "Заставляет предмет оставаться с вами после смерти",
"enchantment.unicopia.consumption": "Потребление", "enchantment.unicopia.consumption": "Потребление",
"enchantment.unicopia.consumption.desc": "Преобразует предметы, добытые с помощью инструмента, в опыт", "enchantment.unicopia.consumption.desc": "Преобразует предметы, добытые с помощью инструмента, в опыт",
"enchantment.unicopia.feather_touch": "Касание пера",
"enchantment.unicopia.feather_touch.desc": "Позволяет ломать и размещать облачные блоки при держании",
"commands.race.success.self": "Изменена раса на %1$s.", "commands.race.success.self": "Изменена раса на %1$s.",
"commands.race.success": "%1$s изменил расу на %2$s.", "commands.race.success": "%1$s изменил расу на %2$s.",
@ -1380,8 +1408,10 @@
"commands.gravity.set": "Ваша гравитация была обновлена до %f", "commands.gravity.set": "Ваша гравитация была обновлена до %f",
"commands.gravity.set.self": "Установить собственную гравитацию на %f", "commands.gravity.set.self": "Установить собственную гравитацию на %f",
"commands.gravity.set.other": "Установить гравитацию %s на %f", "commands.gravity.set.other": "Установить гравитацию %s на %f",
"commands.gravity.set.multiple": "Обновлено %s сущностей",
"unicopia.options.title": "Опции Unicopia", "unicopia.options.title": "Опции Unicopia",
"unicopia.options.toggle_ability_keys": "Нажатие кнопки способности вместо зажатия",
"unicopia.options.ignore_mine_lp": "Игнорировать Mine Little Pony", "unicopia.options.ignore_mine_lp": "Игнорировать Mine Little Pony",
"unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony не установлен", "unicopia.options.ignore_mine_lp.missing": "* Mine Little Pony не установлен",
"unicopia.options.ignore_mine_lp.detected": "* Ваша обнаруженная раса %s", "unicopia.options.ignore_mine_lp.detected": "* Ваша обнаруженная раса %s",
@ -1401,28 +1431,28 @@
"command.unicopia.config.list": "[Config] Свойство (%s) содержит (%s) записей:", "command.unicopia.config.list": "[Config] Свойство (%s) содержит (%s) записей:",
"command.unicopia.config.clear": "[Config] Удалены все значения из свойства %s", "command.unicopia.config.clear": "[Config] Удалены все значения из свойства %s",
"unicopia.race.unset": "Не выбрано", "race.unicopia.unset": "Не выбрано",
"unicopia.race.unset.alt": "не выбрано", "race.unicopia.unset.alt": "не выбрано",
"unicopia.race.human": "Человек", "race.unicopia.human": "Человек",
"unicopia.race.human.alt": "Люди", "race.unicopia.human.alt": "Люди",
"unicopia.race.earth": "Земной пони", "race.unicopia.earth": "Земной пони",
"unicopia.race.earth.alt": "Земные пони", "race.unicopia.earth.alt": "Земные пони",
"unicopia.race.unicorn": "Единорог", "race.unicopia.unicorn": "Единорог",
"unicopia.race.unicorn.alt": "Единороги", "race.unicopia.unicorn.alt": "Единороги",
"unicopia.race.pegasus": "Пегас", "race.unicopia.pegasus": "Пегас",
"unicopia.race.pegasus.alt": "Пегасы", "race.unicopia.pegasus.alt": "Пегасы",
"unicopia.race.alicorn": "Аликорн", "race.unicopia.alicorn": "Аликорн",
"unicopia.race.alicorn.alt": "Аликорны", "race.unicopia.alicorn.alt": "Аликорны",
"unicopia.race.changeling": "Чейнджлинг", "race.unicopia.changeling": "Чейнджлинг",
"unicopia.race.changeling.alt": "Чейнджлинги", "race.unicopia.changeling.alt": "Чейнджлинги",
"unicopia.race.bat": "Бэтпони", "race.unicopia.bat": "Бэтпони",
"unicopia.race.bat.alt": "Бэтпони", "race.unicopia.bat.alt": "Бэтпони",
"unicopia.race.kirin": "Кирин", "race.unicopia.kirin": "Кирин",
"unicopia.race.kirin.alt": "Кирины", "race.unicopia.kirin.alt": "Кирины",
"unicopia.race.hippogriff": "Гиппогриф", "race.unicopia.hippogriff": "Гиппогриф",
"unicopia.race.hippogriff.alt": "Гиппогрифы", "race.unicopia.hippogriff.alt": "Гиппогрифы",
"unicopia.race.seapony": "Морской пони", "race.unicopia.seapony": "Морской пони",
"unicopia.race.seapony.alt": "Морские пони", "race.unicopia.seapony.alt": "Морские пони",
"death.attack.unicopia.generic.and_also": "%1$s и %2$s", "death.attack.unicopia.generic.and_also": "%1$s и %2$s",
"death.attack.unicopia.generic.whilst_flying": "%1$s во время полёта", "death.attack.unicopia.generic.whilst_flying": "%1$s во время полёта",
@ -1592,13 +1622,23 @@
"advancements.unicopia.praise_the_sun.title": "Хвала Солнцу!", "advancements.unicopia.praise_the_sun.title": "Хвала Солнцу!",
"advancements.unicopia.praise_the_sun.description": "Испытайте безудержную славу Селестии", "advancements.unicopia.praise_the_sun.description": "Испытайте безудержную славу Селестии",
"advancements.unicopia.cool_potato.title": "Крутая картошка", "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.title": "Запечённые хлебцы",
"advancements.unicopia.baked_bads.description": "Испеките вкусный маффин", "advancements.unicopia.baked_bads.description": "Испеките вкусный маффин",
"advancements.unicopia.mid_flight_interruption.title": "Побеспокоили в середине полёта", "advancements.unicopia.mid_flight_interruption.title": "Побеспокоили в середине полёта",
"advancements.unicopia.mid_flight_interruption.description": "Получите удар молнии во время полёта в грозу", "advancements.unicopia.mid_flight_interruption.description": "Получите удар молнии во время полёта в грозу",
"advancements.unicopia.lightning_bug.title": "Ошибка молнии", "advancements.unicopia.lightning_bug.title": "Баг молнии",
"advancements.unicopia.lightning_bug.description": "Привлеките 10 ударов молний", "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.title": "О, ничего себе. Что это?",
"advancements.unicopia.jar.description": "Найдите пустую банку", "advancements.unicopia.jar.description": "Найдите пустую банку",
"advancements.unicopia.gotcha.title": "Попался!", "advancements.unicopia.gotcha.title": "Попался!",
@ -1606,11 +1646,17 @@
"advancements.unicopia.trick_apple.title": "Яблоко раздора", "advancements.unicopia.trick_apple.title": "Яблоко раздора",
"advancements.unicopia.trick_apple.description": "Найдите своё первое зап-яблоко", "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.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_trick_apple.description": "Кусните зап-яблоко",
"advancements.unicopia.eat_pinecone.title": "Отчаяние", "advancements.unicopia.eat_pinecone.title": "Отчаяние",
"advancements.unicopia.eat_pinecone.description": "Съешьте шишку", "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.title": "Столь же вкусные, сколь и дорогие",
"advancements.unicopia.imported_oats.description": "Отправьте или получите шикарный импортный овёс", "advancements.unicopia.imported_oats.description": "Отправьте или получите шикарный импортный овёс",
@ -1640,11 +1686,15 @@
"advancements.unicopia.sweet_apple_acres.description": "Получите по одному яблоку каждого сорта", "advancements.unicopia.sweet_apple_acres.description": "Получите по одному яблоку каждого сорта",
"advancements.unicopia.brew_cider.title": "Лучшее от Эпплджек", "advancements.unicopia.brew_cider.title": "Лучшее от Эпплджек",
"advancements.unicopia.brew_cider.description": "Сварить сидр", "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.title": "Путешествие со стилем",
"advancements.unicopia.travelling_in_style.description": "Прокатитесь на воздушном шаре", "advancements.unicopia.travelling_in_style.description": "Прокатитесь на воздушном шаре",
"advancements.unicopia.night_route.title": "Дети Ночи", "advancements.unicopia.bat_route.title": "Дети Ночи",
"advancements.unicopia.night_route.description": "Пойдите по пути ночи", "advancements.unicopia.bat_route.description": "Пойдите по пути ночи",
"advancements.unicopia.screech_twenty_mobs.title": "Ужас с неба", "advancements.unicopia.screech_twenty_mobs.title": "Ужас с неба",
"advancements.unicopia.screech_twenty_mobs.description": "Обрушьте ужас по меньшей мере на 20 мобов одновременно", "advancements.unicopia.screech_twenty_mobs.description": "Обрушьте ужас по меньшей мере на 20 мобов одновременно",
"advancements.unicopia.screech_self.title": "Божечки!", "advancements.unicopia.screech_self.title": "Божечки!",
@ -1657,10 +1707,18 @@
"advancements.unicopia.blasphemy.title": "Кощунство!", "advancements.unicopia.blasphemy.title": "Кощунство!",
"advancements.unicopia.blasphemy.description": "Ударьте Селестию по башке. Упс!", "advancements.unicopia.blasphemy.description": "Ударьте Селестию по башке. Упс!",
"advancements.unicopia.earth_route.title": "Путь Пони", "advancements.unicopia.earth_route.title": "Очаг Земли",
"advancements.unicopia.earth_route.description": "Вступить в клан Яблока", "advancements.unicopia.earth_route.description": "Вступить в клан Яблока",
"advancements.unicopia.sticks_and_stones.title": "Палки и камни", "advancements.unicopia.sticks_and_stones.title": "Палки и камни",
"advancements.unicopia.sticks_and_stones.description": "Убейте моба, бросая в него камни", "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.title": "Звон смерти",
"advancements.unicopia.dead_ringer.description": "Убейте моба подковой", "advancements.unicopia.dead_ringer.description": "Убейте моба подковой",
"advancements.unicopia.born_on_a_rock_farm.title": "Рождённый на Ферме Камней", "advancements.unicopia.born_on_a_rock_farm.title": "Рождённый на Ферме Камней",
@ -1668,14 +1726,32 @@
"advancements.unicopia.thats_unusual.title": "Это необычно", "advancements.unicopia.thats_unusual.title": "Это необычно",
"advancements.unicopia.thats_unusual.description": "Но что оно делает?", "advancements.unicopia.thats_unusual.description": "Но что оно делает?",
"advancements.unicopia.sky_route.title": "Путь Пегаса", "advancements.unicopia.pegasus_route.title": "Путь Пегаса",
"advancements.unicopia.sky_route.description": "Присоединяйтесь к пегасам Клаудсдейла", "advancements.unicopia.pegasus_route.description": "Присоединитесь к пегасам Клаудсдейла",
"advancements.unicopia.molting_season_1.title": "Сезон линьки", "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.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.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.title": "Дискорд тебя побери, Рэйнбоу",
"advancements.unicopia.rainbow_crash.description": "Устройте войну против злой нации стеклянных окон", "advancements.unicopia.rainbow_crash.description": "Устройте войну против злой нации стеклянных окон",
"advancements.unicopia.second_wind.title": "Второе дыхание", "advancements.unicopia.second_wind.title": "Второе дыхание",
@ -1683,11 +1759,13 @@
"advancements.unicopia.deter_phantom.title": "Что летает вокруг", "advancements.unicopia.deter_phantom.title": "Что летает вокруг",
"advancements.unicopia.deter_phantom.description": "Поднимитесь и дайте этим фантомам попробовать их собственное лекарство", "advancements.unicopia.deter_phantom.description": "Поднимитесь и дайте этим фантомам попробовать их собственное лекарство",
"advancements.unicopia.magical_route.title": "Рог единорога", "advancements.unicopia.unicorn_route.title": "Рог единорога",
"advancements.unicopia.magical_route.description": "Окунитесь в мир блеска и радуги", "advancements.unicopia.unicorn_route.description": "Окунитесь в мир блеска и радуги",
"advancements.unicopia.books.title": "Книги!", "advancements.unicopia.books.title": "Книги!",
"advancements.unicopia.books.description": "Это МОЯ книга заклинаний, и я собираюсь её ПРОЧИТАТЬ!", "advancements.unicopia.books.description": "Это МОЯ книга заклинаний, и я собираюсь её ПРОЧИТАТЬ!",
"advancements.unicopia.books_books_books.title": "Книги! Книги! Книги!",
"advancements.unicopia.books_books_books.description": "Заполните инвентарь книгами",
"advancements.unicopia.tempted.title": "Заманчиво...", "advancements.unicopia.tempted.title": "Заманчиво...",
"advancements.unicopia.tempted.description": "Наденьте амулет аликорна", "advancements.unicopia.tempted.description": "Наденьте амулет аликорна",
"advancements.unicopia.hello_darkness_my_old_friend.title": "Здравствуй, Тьма...", "advancements.unicopia.hello_darkness_my_old_friend.title": "Здравствуй, Тьма...",
@ -1710,6 +1788,13 @@
"advancements.unicopia.love_is_power.title": "Любовь - это сила", "advancements.unicopia.love_is_power.title": "Любовь - это сила",
"advancements.unicopia.love_is_power.description": "Изгоните короля Сомбра с помощью кристального сердца", "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.title": "Новые открытия!",
"unicopia.toast.discoveries.description": "Проверьте свою книгу заклинаний" "unicopia.toast.discoveries.description": "Проверьте свою книгу заклинаний"
} }

View file

@ -197,6 +197,7 @@
"item.unicopia.music_disc_funk.desc": "funk, just funk", "item.unicopia.music_disc_funk.desc": "funk, just funk",
"item.unicopia.cloud_lump": "云团", "item.unicopia.cloud_lump": "云团",
"item.unicopia.white_bed_sheets": "白色被单",
"item.unicopia.light_gray_bed_sheets": "淡灰色被单", "item.unicopia.light_gray_bed_sheets": "淡灰色被单",
"item.unicopia.gray_bed_sheets": "灰色被单", "item.unicopia.gray_bed_sheets": "灰色被单",
"item.unicopia.black_bed_sheets": "黑色被单", "item.unicopia.black_bed_sheets": "黑色被单",
@ -228,7 +229,7 @@
"block.unicopia.spectral_fire": "节律火", "block.unicopia.spectral_fire": "节律火",
"block.unicopia.bananas": "香蕉", "block.unicopia.bananas": "香蕉",
"block.unicopia.zapling": "魔虹苹果树苗", "block.unicopia.zapling": "魔虹苹果树苗",
"block.unicopia.potted_zapling": "盆中 魔虹苹果树苗", "block.unicopia.potted_zapling": "魔虹苹果树苗盆栽",
"block.unicopia.zap_log": "魔虹苹果木原木", "block.unicopia.zap_log": "魔虹苹果木原木",
"block.unicopia.zap_wood": "魔虹苹果木", "block.unicopia.zap_wood": "魔虹苹果木",
"block.unicopia.stripped_zap_log": "去皮魔虹苹果木原木", "block.unicopia.stripped_zap_log": "去皮魔虹苹果木原木",
@ -252,7 +253,7 @@
"block.unicopia.zap_apple": "魔虹苹果", "block.unicopia.zap_apple": "魔虹苹果",
"block.unicopia.zap_bulb": "没熟的魔虹苹果", "block.unicopia.zap_bulb": "没熟的魔虹苹果",
"block.unicopia.palm_sapling": "棕榈树苗", "block.unicopia.palm_sapling": "棕榈树苗",
"block.unicopia.potted_palm_sapling": "盆中 棕榈树苗", "block.unicopia.potted_palm_sapling": "棕榈树苗盆栽",
"block.unicopia.palm_log": "棕榈木原木", "block.unicopia.palm_log": "棕榈木原木",
"block.unicopia.palm_wood": "棕榈木", "block.unicopia.palm_wood": "棕榈木",
"block.unicopia.palm_planks": "棕榈木板", "block.unicopia.palm_planks": "棕榈木板",
@ -275,13 +276,13 @@
"block.unicopia.gold_root": "黄金根", "block.unicopia.gold_root": "黄金根",
"block.unicopia.golden_oak_sprout": "金橡树嫩芽", "block.unicopia.golden_oak_sprout": "金橡树嫩芽",
"block.unicopia.golden_oak_sapling": "金橡树树苗", "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_leaves": "金橡树树叶",
"block.unicopia.golden_oak_log": "金橡树原木", "block.unicopia.golden_oak_log": "金橡树原木",
"block.unicopia.mango": "芒果", "block.unicopia.mango": "芒果",
"block.unicopia.mango_leaves": "芒果树叶", "block.unicopia.mango_leaves": "芒果树叶",
"block.unicopia.mango_sapling": "芒果树苗", "block.unicopia.mango_sapling": "芒果树苗",
"block.unicopia.potted_mango_sapling": "盆中 芒果树苗", "block.unicopia.potted_mango_sapling": "芒果树苗盆栽",
"block.unicopia.pineapple": "菠萝树", "block.unicopia.pineapple": "菠萝树",
"block.unicopia.clam_shell": "蛤蜊壳", "block.unicopia.clam_shell": "蛤蜊壳",
@ -290,15 +291,15 @@
"block.unicopia.green_apple_leaves": "史密斯婆婆苹果树树叶", "block.unicopia.green_apple_leaves": "史密斯婆婆苹果树树叶",
"block.unicopia.green_apple_sapling": "史密斯婆婆苹果树树苗", "block.unicopia.green_apple_sapling": "史密斯婆婆苹果树树苗",
"block.unicopia.potted_green_apple_sapling": "盆中 史密斯婆婆苹果树树苗", "block.unicopia.potted_green_apple_sapling": "史密斯婆婆苹果树树苗盆栽",
"block.unicopia.green_apple_sprout": "史密斯婆婆苹果嫩芽", "block.unicopia.green_apple_sprout": "史密斯婆婆苹果嫩芽",
"block.unicopia.sweet_apple_leaves": "甜苹果树树叶", "block.unicopia.sweet_apple_leaves": "甜苹果树树叶",
"block.unicopia.sweet_apple_sapling": "甜苹果树树苗", "block.unicopia.sweet_apple_sapling": "甜苹果树树苗",
"block.unicopia.potted_sweet_apple_sapling": "盆中 甜苹果树树苗", "block.unicopia.potted_sweet_apple_sapling": "甜苹果树树苗盆栽",
"block.unicopia.sweet_apple_sprout": "甜苹果树嫩芽", "block.unicopia.sweet_apple_sprout": "甜苹果树嫩芽",
"block.unicopia.sour_apple_leaves": "酸苹果树树叶", "block.unicopia.sour_apple_leaves": "酸苹果树树叶",
"block.unicopia.sour_apple_sapling": "酸苹果树树苗", "block.unicopia.sour_apple_sapling": "酸苹果树树苗",
"block.unicopia.potted_sour_apple_sapling": "盆中 酸苹果树树苗", "block.unicopia.potted_sour_apple_sapling": "酸苹果树树苗盆栽",
"block.unicopia.sour_apple_sprout": "酸苹果树嫩芽", "block.unicopia.sour_apple_sprout": "酸苹果树嫩芽",
"block.unicopia.surface_chitin": "几丁质表面", "block.unicopia.surface_chitin": "几丁质表面",
@ -612,6 +613,7 @@
"tag.unicopia.food_types.cooked_fish": "烤好的鱼", "tag.unicopia.food_types.cooked_fish": "烤好的鱼",
"tag.unicopia.food_types.raw_insect": "虫类", "tag.unicopia.food_types.raw_insect": "虫类",
"tag.unicopia.food_types.cooked_insect": "烤虫类", "tag.unicopia.food_types.cooked_insect": "烤虫类",
"tag.unicopia.food_types.nuts_and_seeds": "坚果和种子",
"tag.unicopia.food_types.love": "爱", "tag.unicopia.food_types.love": "爱",
"tag.unicopia.food_types.rocks": "石块", "tag.unicopia.food_types.rocks": "石块",
"tag.unicopia.food_types.pinecone": "坚果和种子", "tag.unicopia.food_types.pinecone": "坚果和种子",
@ -1547,6 +1549,7 @@
"unicopia.subtitle.pegasus.molt": "天马:脱羽", "unicopia.subtitle.pegasus.molt": "天马:脱羽",
"unicopia.subtitle.unicorn.teleport": "魔法:啵", "unicopia.subtitle.unicorn.teleport": "魔法:啵",
"unicopia.subtitle.player.wololo": "Wololo", "unicopia.subtitle.player.wololo": "Wololo",
"unicopia.subtitle.corrupt": "魔法:堕落",
"unicopia.subtitle.entity.player.whistle": "玩家吹口哨", "unicopia.subtitle.entity.player.whistle": "玩家吹口哨",
"unicopia.subtitle.entity.player.kick": "玩家:踢腿", "unicopia.subtitle.entity.player.kick": "玩家:踢腿",
"unicopia.subtitle.magic_aura": "魔法:嗡嗡", "unicopia.subtitle.magic_aura": "魔法:嗡嗡",
@ -1591,12 +1594,18 @@
"advancements.unicopia.praise_the_sun.description": "感受太阳公主的无上熔光", "advancements.unicopia.praise_the_sun.description": "感受太阳公主的无上熔光",
"advancements.unicopia.cool_potato.title": "酷毙了", "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.baked_bads.title": "烤砸了", "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.title": "风雷混合双打",
"advancements.unicopia.mid_flight_interruption.description": "在风暴中飞行时被雷劈到", "advancements.unicopia.mid_flight_interruption.description": "在风暴中飞行时被雷劈到",
"advancements.unicopia.lightning_bug.title": "引火虫", "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.title": "哇哦,这是什么?",
"advancements.unicopia.jar.description": "找到一个空罐子", "advancements.unicopia.jar.description": "找到一个空罐子",
"advancements.unicopia.gotcha.title": "抓到你了!", "advancements.unicopia.gotcha.title": "抓到你了!",
@ -1669,15 +1678,33 @@
"advancements.unicopia.sky_route.title": "飞彳亍", "advancements.unicopia.sky_route.title": "飞彳亍",
"advancements.unicopia.sky_route.description": "入驻云中城", "advancements.unicopia.sky_route.description": "入驻云中城",
"advancements.unicopia.molting_season_1.title": "换羽季节I", "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.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.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.title": "去你的彩虹",
"advancements.unicopia.rainbow_crash.description": "向邪恶的玻璃国宣战", "advancements.unicopia.rainbow_crash.description": "向邪恶的玻璃国宣战",
"advancements.unicopia.second_wind.title": "来劲了", "advancements.unicopia.second_wind.title": "来劲了",
"advancements.unicopia.second_wind.description": "竭力飞行", "advancements.unicopia.second_wind.description": "难受啊马飞",
"advancements.unicopia.deter_phantom.title": "神仙斗法", "advancements.unicopia.deter_phantom.title": "神仙斗法",
"advancements.unicopia.deter_phantom.description": "马飞飞,让那些修仙的幻翼永远安眠吧", "advancements.unicopia.deter_phantom.description": "马飞飞,让那些修仙的幻翼永远安眠吧",

View file

@ -6,13 +6,13 @@
"sleep.not_possible.nocturnal": "您無法跳過這一天", "sleep.not_possible.nocturnal": "您無法跳過這一天",
"sleep.skipping_day": "這一天將在睡夢中度過", "sleep.skipping_day": "這一天將在睡夢中度過",
"ability.unicopia.empty_hooves": "我需要找到一個罐子", "ability.unicopia.empty_hooves": "我需要一個罐子",
"ability.unicopia.indoors": "我在這裏看不到天空", "ability.unicopia.indoors": "我在這裏看不到天空",
"ability.unicopia.too_low": "我要飛得更高", "ability.unicopia.too_low": "我要飛得更高",
"ability.unicopia.clear_skies": "天空看起來已經很晴朗了", "ability.unicopia.clear_skies": "天空已經很晴朗了",
"ability.unicopia.too_calm.1": "我需要更加憤怒……", "ability.unicopia.too_calm.1": "我的怒火要更加旺盛一些……",
"ability.unicopia.too_calm.2": "我並不感到憤怒……", "ability.unicopia.too_calm.2": "我並不怎麼生氣……",
"ability.unicopia.too_calm.3": "李小龍這看着好輕鬆啊……", "ability.unicopia.too_calm.3": "李小龍麼做看着好輕鬆啊……",
"ability.unicopia.too_calm.4": "塞蕾斯蒂亞公主,請賜予我力量……", "ability.unicopia.too_calm.4": "塞蕾斯蒂亞公主,請賜予我力量……",
"itemGroup.unicopia.items": "Unicopia", "itemGroup.unicopia.items": "Unicopia",
@ -49,6 +49,9 @@
"emi.category.unicopia.spellbook": "咒語書", "emi.category.unicopia.spellbook": "咒語書",
"emi.category.unicopia.cloud_shaping": "塑形", "emi.category.unicopia.cloud_shaping": "塑形",
"emi.category.unicopia.growing": "生長", "emi.category.unicopia.growing": "生長",
"emi.category.unicopia.altar": "黑暗儀式",
"recipe.unicopia.altar.instruction": "火焰侵蝕物品",
"recipe.unicopia.growing.instruction": "聚焦陸馬魔法",
"item.unicopia.alicorn_badge": "天角徽章", "item.unicopia.alicorn_badge": "天角徽章",
"item.unicopia.unicorn_badge": "獨角徽章", "item.unicopia.unicorn_badge": "獨角徽章",
@ -79,9 +82,9 @@
"item.unicopia.plunder_vine": "掠奪藤蔓", "item.unicopia.plunder_vine": "掠奪藤蔓",
"item.unicopia.empty_jar": "玻璃罐", "item.unicopia.empty_jar": "玻璃罐",
"item.unicopia.filled_jar": "%s罐", "item.unicopia.filled_jar": "%s罐",
"item.unicopia.rain_cloud_jar": "雨罐", "item.unicopia.rain_cloud_jar": "雨罐",
"item.unicopia.storm_cloud_jar": "暴雨罐", "item.unicopia.storm_cloud_jar": "暴雨罐",
"item.unicopia.lightning_jar": "電罐", "item.unicopia.lightning_jar": "電罐",
"item.unicopia.zap_apple_jam_jar": "彩虹蘋果醬罐", "item.unicopia.zap_apple_jam_jar": "彩虹蘋果醬罐",
"item.unicopia.toast": "烤麪包片", "item.unicopia.toast": "烤麪包片",
@ -156,7 +159,7 @@
"item.unicopia.clam_shell": "蛤殼", "item.unicopia.clam_shell": "蛤殼",
"item.unicopia.scallop_shell": "貝殼", "item.unicopia.scallop_shell": "貝殼",
"item.unicopia.turret_shell": "塔殼", "item.unicopia.turret_shell": "塔殼",
"item.unicopia.shelly": "小殼", "item.unicopia.shelly": "螺螺",
"item.unicopia.horse_shoe.accuracy": "精準度:%d%%", "item.unicopia.horse_shoe.accuracy": "精準度:%d%%",
"item.unicopia.horse_shoe.speed": "速度:%d", "item.unicopia.horse_shoe.speed": "速度:%d",
@ -194,6 +197,7 @@
"item.unicopia.music_disc_funk.desc": "Death by Glamour", "item.unicopia.music_disc_funk.desc": "Death by Glamour",
"item.unicopia.cloud_lump": "雲塊", "item.unicopia.cloud_lump": "雲塊",
"item.unicopia.white_bed_sheets": "白色被單",
"item.unicopia.light_gray_bed_sheets": "淡灰被單", "item.unicopia.light_gray_bed_sheets": "淡灰被單",
"item.unicopia.gray_bed_sheets": "灰色被單", "item.unicopia.gray_bed_sheets": "灰色被單",
"item.unicopia.black_bed_sheets": "黑色被單", "item.unicopia.black_bed_sheets": "黑色被單",
@ -222,17 +226,34 @@
"block.unicopia.rocks": "岩石", "block.unicopia.rocks": "岩石",
"block.unicopia.plunder_vine": "掠奪藤蔓", "block.unicopia.plunder_vine": "掠奪藤蔓",
"block.unicopia.plunder_vine_bud": "掠奪藤蔓芽", "block.unicopia.plunder_vine_bud": "掠奪藤蔓芽",
"block.unicopia.spectral_fire": "光譜火焰",
"block.unicopia.bananas": "香蕉", "block.unicopia.bananas": "香蕉",
"block.unicopia.zapling": "彩虹蘋果苗", "block.unicopia.zapling": "彩虹蘋果苗",
"block.unicopia.potted_zapling": "彩虹蘋果苗盆栽",
"block.unicopia.zap_log": "彩虹蘋果原木", "block.unicopia.zap_log": "彩虹蘋果原木",
"block.unicopia.zap_wood": "彩虹蘋果木塊", "block.unicopia.zap_wood": "彩虹蘋果木塊",
"block.unicopia.stripped_zap_log": "剝皮彩虹蘋果原木", "block.unicopia.stripped_zap_log": "剝皮彩虹蘋果原木",
"block.unicopia.stripped_zap_wood": "剝皮彩虹蘋果木塊", "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.zap_leaves": "彩虹蘋果樹葉",
"block.unicopia.flowering_zap_leaves": "開花彩虹蘋果樹葉", "block.unicopia.flowering_zap_leaves": "開花彩虹蘋果樹葉",
"block.unicopia.zap_apple": "彩虹蘋果", "block.unicopia.zap_apple": "彩虹蘋果",
"block.unicopia.zap_bulb": "生彩虹蘋果", "block.unicopia.zap_bulb": "生彩虹蘋果",
"block.unicopia.palm_sapling": "棕櫚苗", "block.unicopia.palm_sapling": "棕櫚苗",
"block.unicopia.potted_palm_sapling": "棕櫚苗盆栽",
"block.unicopia.palm_log": "棕櫚原木", "block.unicopia.palm_log": "棕櫚原木",
"block.unicopia.palm_wood": "棕櫚木塊", "block.unicopia.palm_wood": "棕櫚木塊",
"block.unicopia.palm_planks": "棕櫚木材", "block.unicopia.palm_planks": "棕櫚木材",
@ -255,11 +276,13 @@
"block.unicopia.gold_root": "金橡樹根", "block.unicopia.gold_root": "金橡樹根",
"block.unicopia.golden_oak_sprout": "金橡樹芽", "block.unicopia.golden_oak_sprout": "金橡樹芽",
"block.unicopia.golden_oak_sapling": "金橡樹苗", "block.unicopia.golden_oak_sapling": "金橡樹苗",
"block.unicopia.potted_golden_oak_sapling": "金橡樹苗盆栽",
"block.unicopia.golden_oak_leaves": "金橡樹葉", "block.unicopia.golden_oak_leaves": "金橡樹葉",
"block.unicopia.golden_oak_log": "金橡樹原木", "block.unicopia.golden_oak_log": "金橡樹原木",
"block.unicopia.mango": "芒果", "block.unicopia.mango": "芒果",
"block.unicopia.mango_leaves": "芒果葉", "block.unicopia.mango_leaves": "芒果葉",
"block.unicopia.mango_sapling": "芒果葉", "block.unicopia.mango_sapling": "芒果苗",
"block.unicopia.potted_mango_sapling": "芒果苗盆栽",
"block.unicopia.pineapple": "鳳梨株", "block.unicopia.pineapple": "鳳梨株",
"block.unicopia.clam_shell": "蛤殼", "block.unicopia.clam_shell": "蛤殼",
@ -268,12 +291,15 @@
"block.unicopia.green_apple_leaves": "婆婆蘋果樹葉", "block.unicopia.green_apple_leaves": "婆婆蘋果樹葉",
"block.unicopia.green_apple_sapling": "婆婆蘋果苗", "block.unicopia.green_apple_sapling": "婆婆蘋果苗",
"block.unicopia.potted_green_apple_sapling": "婆婆蘋果苗盆栽",
"block.unicopia.green_apple_sprout": "婆婆蘋果芽", "block.unicopia.green_apple_sprout": "婆婆蘋果芽",
"block.unicopia.sweet_apple_leaves": "香甜蘋果樹葉", "block.unicopia.sweet_apple_leaves": "香甜蘋果樹葉",
"block.unicopia.sweet_apple_sapling": "香甜蘋果苗", "block.unicopia.sweet_apple_sapling": "香甜蘋果苗",
"block.unicopia.potted_sweet_apple_sapling": "香甜蘋果苗盆栽",
"block.unicopia.sweet_apple_sprout": "香甜蘋果芽", "block.unicopia.sweet_apple_sprout": "香甜蘋果芽",
"block.unicopia.sour_apple_leaves": "酸蘋果樹葉", "block.unicopia.sour_apple_leaves": "酸蘋果樹葉",
"block.unicopia.sour_apple_sapling": "酸蘋果苗", "block.unicopia.sour_apple_sapling": "酸蘋果苗",
"block.unicopia.potted_sour_apple_sapling": "酸蘋果苗盆栽",
"block.unicopia.sour_apple_sprout": "酸蘋果芽", "block.unicopia.sour_apple_sprout": "酸蘋果芽",
"block.unicopia.surface_chitin": "表殼", "block.unicopia.surface_chitin": "表殼",
@ -575,8 +601,8 @@
"unicopia.diet.side_effects": "副作用:", "unicopia.diet.side_effects": "副作用:",
"unicopia.diet.not_edible": "物品不可食用", "unicopia.diet.not_edible": "物品不可食用",
"unicopia.diet.base_multiplier": "基礎倍增:%s%%", "unicopia.diet.base_multiplier": "基礎倍增:%s%%",
"unicopia.diet.hunger.detailed": "獲得飢餓:%s of %s (%s%%)", "unicopia.diet.hunger.detailed": "獲得飢餓:%s分之%s (%s%%)",
"unicopia.diet.saturation.detailed": "獲得飽食: %s (%s%%)", "unicopia.diet.saturation.detailed": "獲得飽食: %s分之%s (%s%%)",
"unicopia.diet.hunger": "飢餓比:%s%%", "unicopia.diet.hunger": "飢餓比:%s%%",
"unicopia.diet.saturation": "飽食比:%s%%", "unicopia.diet.saturation": "飽食比:%s%%",
@ -587,6 +613,7 @@
"tag.unicopia.food_types.cooked_fish": "熟魚", "tag.unicopia.food_types.cooked_fish": "熟魚",
"tag.unicopia.food_types.raw_insect": "蟲", "tag.unicopia.food_types.raw_insect": "蟲",
"tag.unicopia.food_types.cooked_insect": "熟蟲", "tag.unicopia.food_types.cooked_insect": "熟蟲",
"tag.unicopia.food_types.nuts_and_seeds": "堅果與種子",
"tag.unicopia.food_types.love": "愛意", "tag.unicopia.food_types.love": "愛意",
"tag.unicopia.food_types.rocks": "岩石", "tag.unicopia.food_types.rocks": "岩石",
"tag.unicopia.food_types.pinecone": "堅果與種子", "tag.unicopia.food_types.pinecone": "堅果與種子",
@ -594,11 +621,15 @@
"tag.unicopia.food_types.cooked_sea_vegitables": "熟魚食", "tag.unicopia.food_types.cooked_sea_vegitables": "熟魚食",
"tag.unicopia.food_types.raw_sea_vegitables": "鮮魚食", "tag.unicopia.food_types.raw_sea_vegitables": "鮮魚食",
"tag.unicopia.food_types.shells": "海螺", "tag.unicopia.food_types.shells": "海螺",
"tag.unicopia.food_types.shelly": "螺", "tag.unicopia.food_types.shelly": "螺",
"tag.unicopia.food_types.candy": "糖果", "tag.unicopia.food_types.candy": "糖果",
"tag.unicopia.food_types.desserts": "點心", "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.fruits_and_vegetables": "水果與蔬菜",
"tag.unicopia.food_types.drinks": "飲料", "tag.unicopia.food_types.drinks": "飲料",
"tag.minecraft.leaves": "葉類",
"tag.unicopia.food_types.forage_edible_filling": "大型植質", "tag.unicopia.food_types.forage_edible_filling": "大型植質",
"tag.unicopia.food_types.forage_edible": "植質", "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.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.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.1.unicopia.changeling": " - 一直餓肚子",
"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.2.unicopia.changeling": " - 需要從其他小馬或敵對生物吸取愛意來填飽肚子",
"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.3.unicopia.changeling": " - 吃絕大多數普通食物會生病,必須收穫愛意來治癒",
"gui.unicopia.tribe_selection.confirm.bads.1.unicopia.kirin": " - Are no longer quiet whilst raging", "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.kirin": " - 發火時不再安靜",
"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.2.unicopia.kirin": " - 傾向于燒東西,尤其是在發火時",
"gui.unicopia.tribe_selection.confirm.bads.3.unicopia.kirin": " - Lighter than other ponies, and might take increased knockback", "gui.unicopia.tribe_selection.confirm.bads.3.unicopia.kirin": " - 比其他小馬輕盈,可能更容易被擊退",
"gui.unicopia.tribe_selection.confirm.bads.4.unicopia.kirin": " - Doesn't like water", "gui.unicopia.tribe_selection.confirm.bads.4.unicopia.kirin": " - 不喜歡水",
"gui.unicopia.tribe_selection.confirm.bads.1.unicopia.hippogriff": " - 易受蠻力攻擊", "gui.unicopia.tribe_selection.confirm.bads.1.unicopia.hippogriff": " - 易受蠻力攻擊",
"gui.unicopia.tribe_selection.confirm.bads.2.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.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.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.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.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.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.", "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.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.torn_page.3.body": "Building Materials:",
"gui.unicopia.spellbook.chapter.artefacts.crystal_podium.title": "Crystal Podium", "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.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.title": "2nd Hoof '12",
"gui.unicopia.spellbook.chapter.artefacts.dragon_breath_scroll.3.body": "P.S. Uncle Starswirly is a dunderhead.", "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.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.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.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.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.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", "gui.unicopia.spellbook.chapter.artefacts.pegasus_amulet.title": "21st Trot '12",
@ -1155,16 +1191,16 @@
"gui.unicopia.action.spells_cleared": "已移除所有魔咒", "gui.unicopia.action.spells_cleared": "已移除所有魔咒",
"gui.unicopia.action.no_spells_cleared": "您沒有活躍的魔咒", "gui.unicopia.action.no_spells_cleared": "您沒有活躍的魔咒",
"chapter.unicopia.crafting": "Spell Crafting", "chapter.unicopia.crafting": "咒語合成",
"chapter.unicopia.profile": "Profile", "chapter.unicopia.profile": "總概",
"chapter.unicopia.traits": "Research", "chapter.unicopia.traits": "研究",
"chapter.unicopia.introduction": "Introduction", "chapter.unicopia.introduction": "介紹",
"chapter.unicopia.fire_magic": "Fire Magic", "chapter.unicopia.fire_magic": "火咒",
"chapter.unicopia.ice_magic": "Ice Magic", "chapter.unicopia.ice_magic": "冰咒",
"chapter.unicopia.air_magic": "Air Magic", "chapter.unicopia.air_magic": "氣咒",
"chapter.unicopia.dark_magic": "Dark Magic", "chapter.unicopia.dark_magic": "暗咒",
"chapter.unicopia.the_otherworldly": "Forbidden Magic", "chapter.unicopia.the_otherworldly": "禁咒",
"chapter.unicopia.crystal_heart": "Artifacts", "chapter.unicopia.crystal_heart": "神器",
"experience.unicopia.pure.magical_kindergartner": "New Blood", "experience.unicopia.pure.magical_kindergartner": "New Blood",
"experience.unicopia.impure.magical_kindergartner": "Impure", "experience.unicopia.impure.magical_kindergartner": "Impure",
@ -1250,19 +1286,19 @@
"experience.unicopia.corrupt.alicorn_princess": "Shadowy Alicorn Lord", "experience.unicopia.corrupt.alicorn_princess": "Shadowy Alicorn Lord",
"experience.unicopia.monstrous.alicorn_princess": "Dark Alicorn Lord", "experience.unicopia.monstrous.alicorn_princess": "Dark Alicorn Lord",
"experience.unicopia.pure.polycorn_princess": "Polycorn Princess", "experience.unicopia.pure.polycorn_princess": "多角公主",
"experience.unicopia.impure.polycorn_princess": "Impure Polycorn Princess", "experience.unicopia.impure.polycorn_princess": "不潔多角公主",
"experience.unicopia.tainted.polycorn_princess": "Tainted Polycorn Princess", "experience.unicopia.tainted.polycorn_princess": "髒污多角公主",
"experience.unicopia.twisted.polycorn_princess": "Fallen Polycorn Princess", "experience.unicopia.twisted.polycorn_princess": "墮落多角公主",
"experience.unicopia.corrupt.polycorn_princess": "Shadowy Polycorn King", "experience.unicopia.corrupt.polycorn_princess": "暗影多角王子",
"experience.unicopia.monstrous.polycorn_princess": "Dark Polycorn King", "experience.unicopia.monstrous.polycorn_princess": "暗黑多角王子",
"experience.unicopia.pure.faustian_legend": "Hero of Legend", "experience.unicopia.pure.faustian_legend": "史詩傳奇",
"experience.unicopia.impure.faustian_legend": "Legendary", "experience.unicopia.impure.faustian_legend": "名垂青史",
"experience.unicopia.tainted.faustian_legend": "Storied Figure of Distant Descent", "experience.unicopia.tainted.faustian_legend": "墮落傳說",
"experience.unicopia.twisted.faustian_legend": "Dark Figure of Lore", "experience.unicopia.twisted.faustian_legend": "暗黑傳說",
"experience.unicopia.corrupt.faustian_legend": "The Old God", "experience.unicopia.corrupt.faustian_legend": "上古惡神",
"experience.unicopia.monstrous.faustian_legend": "Otherworldly Terror", "experience.unicopia.monstrous.faustian_legend": "異世魔王",
"unicopia.category.name": "小馬能力", "unicopia.category.name": "小馬能力",
@ -1275,16 +1311,27 @@
"key.unicopia.hud_page_up": "介面下一頁", "key.unicopia.hud_page_up": "介面下一頁",
"enchantment.unicopia.gem_finder": "尋礦", "enchantment.unicopia.gem_finder": "尋礦",
"enchantment.unicopia.gem_finder.desc": "靠近高價值礦物時發出嗡嗡聲",
"enchantment.unicopia.padded": "衝擊保護", "enchantment.unicopia.padded": "衝擊保護",
"enchantment.unicopia.padded.desc": "撞牆時從牆上彈開,爲您飛行護航",
"enchantment.unicopia.clingy": "纏身", "enchantment.unicopia.clingy": "纏身",
"enchantment.unicopia.clingy.desc": "物品掉落後緊隨玩家",
"enchantment.unicopia.repulsion": "輕盈", "enchantment.unicopia.repulsion": "輕盈",
"enchantment.unicopia.repulsion.desc": "身輕如燕",
"enchantment.unicopia.heavy": "沉重", "enchantment.unicopia.heavy": "沉重",
"enchantment.unicopia.heavy.desc": "讓穿戴盔甲的有翼種族更沉重,更難被魔法和風推動",
"enchantment.unicopia.herds": "合擊", "enchantment.unicopia.herds": "合擊",
"enchantment.unicopia.herds.desc": "盟友更多,力量更強",
"enchantment.unicopia.want_it_need_it": "爭奪詛咒", "enchantment.unicopia.want_it_need_it": "爭奪詛咒",
"enchantment.unicopia.want_it_need_it.desc": "生物無法抵抗對帶此魔咒的物品的誘惑",
"enchantment.unicopia.poisoned_joke": "毒笑", "enchantment.unicopia.poisoned_joke": "毒笑",
"enchantment.unicopia.poisoned_joke.desc": "使用者會不時幻聽",
"enchantment.unicopia.stressed": "重壓", "enchantment.unicopia.stressed": "重壓",
"enchantment.unicopia.stressed.desc": "危險時搖晃熒幕",
"enchantment.unicopia.heart_bound": "赤膽忠心", "enchantment.unicopia.heart_bound": "赤膽忠心",
"enchantment.unicopia.heart_bound.desc": "死後物品仍然陪伴著你",
"enchantment.unicopia.consumption": "經驗轉化", "enchantment.unicopia.consumption": "經驗轉化",
"enchantment.unicopia.consumption.desc": "使用帶本魔咒的工具挖掘時,掉落物化爲經驗",
"commands.race.success.self": "將自己的種族設爲%1$s", "commands.race.success.self": "將自己的種族設爲%1$s",
"commands.race.success": "%1$s將種族變爲%2$s", "commands.race.success": "%1$s將種族變爲%2$s",
@ -1303,16 +1350,23 @@
"commands.race.tell.other.alt": "%s是", "commands.race.tell.other.alt": "%s是",
"commands.racelist.illegal": "默認的種族%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": "已將%1$s加入白名單。",
"commands.racelist.allowed.failed": "%1$s已在白名單內。", "commands.racelist.allowed.failed": "%1$s已在白名單內。",
"commands.racelist.inactive": "白名單並未啓用。執行/unicopia racelist <allow|disallow> <種族> 指令以對其進行配置。",
"commands.racelist.disallowed": "將%1$s從白名單移除", "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.get": "當前所有新玩家的預設種族爲:%s",
"commands.worldtribe.success.set": "將新玩家的預設種族設爲:%s", "commands.worldtribe.success.set": "將新玩家的預設種族設爲:%s",
"commands.disguise.usage": "/disguise <玩家> <實體> [nbt]",
"commands.disguise.notfound": "實體ID「%s」不存在。", "commands.disguise.notfound": "實體ID「%s」不存在。",
"commands.disguise.removed": "您的僞裝已被移除。", "commands.disguise.removed": "您的僞裝已被移除。",
"commands.disguise.removed.self": "移除了自己的僞裝。", "commands.disguise.removed.self": "移除了自己的僞裝。",
@ -1438,6 +1492,8 @@
"death.attack.unicopia.horseshoe.self": "%1$s把自己敲死了", "death.attack.unicopia.horseshoe.self": "%1$s把自己敲死了",
"death.attack.unicopia.horseshoe.item": "%1$s被%2$s用%3$s敲死了", "death.attack.unicopia.horseshoe.item": "%1$s被%2$s用%3$s敲死了",
"death.attack.unicopia.horseshoe.player": "%1$s被%2$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.ladder.pegasus": "%1$s忘記了自己能飛掉下了梯子",
"death.fell.accident.vines.pegasus": "%1$s忘記了自己能飛掉下了藤蔓", "death.fell.accident.vines.pegasus": "%1$s忘記了自己能飛掉下了藤蔓",
@ -1492,6 +1548,7 @@
"unicopia.subtitle.pegasus.molt": "飛馬:掉落羽毛", "unicopia.subtitle.pegasus.molt": "飛馬:掉落羽毛",
"unicopia.subtitle.unicorn.teleport": "魔法:傳送", "unicopia.subtitle.unicorn.teleport": "魔法:傳送",
"unicopia.subtitle.player.wololo": "喔囉囉!", "unicopia.subtitle.player.wololo": "喔囉囉!",
"unicopia.subtitle.corrupt": "魔法:墮落",
"unicopia.subtitle.entity.player.whistle": "玩家:吹口哨", "unicopia.subtitle.entity.player.whistle": "玩家:吹口哨",
"unicopia.subtitle.entity.player.kick": "玩家:踢", "unicopia.subtitle.entity.player.kick": "玩家:踢",
"unicopia.subtitle.magic_aura": "魔法:低鳴", "unicopia.subtitle.magic_aura": "魔法:低鳴",
@ -1544,13 +1601,13 @@
"advancements.unicopia.lightning_bug.description": "被雷劈十次", "advancements.unicopia.lightning_bug.description": "被雷劈十次",
"advancements.unicopia.jar.title": "哇,這是什麼?", "advancements.unicopia.jar.title": "哇,這是什麼?",
"advancements.unicopia.jar.description": "找到一個空罐子", "advancements.unicopia.jar.description": "找到一個空罐子",
"advancements.unicopia.gotcha.title": "抓到", "advancements.unicopia.gotcha.title": "抓到你了",
"advancements.unicopia.gotcha.description": "捕獲暴雨", "advancements.unicopia.gotcha.description": "捕獲暴雨",
"advancements.unicopia.trick_apple.title": "無序林檎", "advancements.unicopia.trick_apple.title": "無序林檎",
"advancements.unicopia.trick_apple.description": "找到你的第一個彩虹蘋果", "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.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_trick_apple.description": "吃下彩虹蘋果",
"advancements.unicopia.eat_pinecone.title": "走投無路", "advancements.unicopia.eat_pinecone.title": "走投無路",
"advancements.unicopia.eat_pinecone.description": "吃下松果", "advancements.unicopia.eat_pinecone.description": "吃下松果",
@ -1569,7 +1626,7 @@
"advancements.unicopia.burn_juice.title": "不太對勁", "advancements.unicopia.burn_juice.title": "不太對勁",
"advancements.unicopia.burn_juice.description": "將蘋果汁烤糊", "advancements.unicopia.burn_juice.description": "將蘋果汁烤糊",
"advancements.unicopia.apple_route.title": "蘋果、蘋果、蘋果", "advancements.unicopia.apple_route.title": "林檎傳說",
"advancements.unicopia.apple_route.description": "開啓你的蘋果傳奇遊記", "advancements.unicopia.apple_route.description": "開啓你的蘋果傳奇遊記",
"advancements.unicopia.juice.title": "清爽", "advancements.unicopia.juice.title": "清爽",
"advancements.unicopia.juice.description": "這些蘋果終於有用了", "advancements.unicopia.juice.description": "這些蘋果終於有用了",
@ -1639,7 +1696,7 @@
"advancements.unicopia.a_falling_wizard.description": "一個施飛行咒失敗的獨角", "advancements.unicopia.a_falling_wizard.description": "一個施飛行咒失敗的獨角",
"advancements.unicopia.split_the_sea.title": "你叫什麼,摩西嗎?", "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.title": "拯救世界",
"advancements.unicopia.save_the_day.description": "擊敗黑晶王", "advancements.unicopia.save_the_day.description": "擊敗黑晶王",
"advancements.unicopia.ascension.title": "原地昇天", "advancements.unicopia.ascension.title": "原地昇天",

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -2,6 +2,7 @@
"replace": false, "replace": false,
"values": [ "values": [
"unicopia:magical_exhaustion", "unicopia:magical_exhaustion",
"unicopia:gravity_well_recoil",
"unicopia:alicorn_amulet", "unicopia:alicorn_amulet",
"unicopia:zap", "unicopia:zap",
"unicopia:kick", "unicopia:kick",

View file

@ -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/render/VertexConsumers$Union
accessible class net/minecraft/client/gui/hud/InGameHud$HeartType 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 <init> (Lcom/mojang/serialization/Codec;)V accessible method net/minecraft/world/gen/foliage/FoliagePlacerType <init> (Lcom/mojang/serialization/Codec;)V
accessible field net/minecraft/entity/mob/CreeperEntity CHARGED Lnet/minecraft/entity/data/TrackedData; accessible field net/minecraft/entity/mob/CreeperEntity CHARGED Lnet/minecraft/entity/data/TrackedData;