mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-24 05:47:59 +01:00
Implement proper composition of abilities when wearing the alicorn amulet
This commit is contained in:
parent
da107e7b81
commit
a1268e8209
12 changed files with 47 additions and 24 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia;
|
package com.minelittlepony.unicopia;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
@ -197,6 +198,16 @@ public final class Race implements Affine {
|
||||||
public static Set<Race> allPermitted(PlayerEntity player) {
|
public static Set<Race> allPermitted(PlayerEntity player) {
|
||||||
return REGISTRY.stream().filter(r -> r.isPermitted(player)).collect(Collectors.toSet());
|
return REGISTRY.stream().filter(r -> r.isPermitted(player)).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record Composite (Race physical, Race pseudo) {
|
||||||
|
public boolean includes(Race race) {
|
||||||
|
return physical == race || pseudo == race;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean any(Predicate<Race> test) {
|
||||||
|
return test.test(physical) || test.test(pseudo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,16 @@ import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.util.Registries;
|
import com.minelittlepony.unicopia.util.Registries;
|
||||||
|
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.*;
|
||||||
import net.minecraft.util.Util;
|
|
||||||
import net.minecraft.util.registry.Registry;
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
public interface Abilities {
|
public interface Abilities {
|
||||||
Registry<Ability<?>> REGISTRY = Registries.createSimple(Unicopia.id("abilities"));
|
Registry<Ability<?>> REGISTRY = Registries.createSimple(Unicopia.id("abilities"));
|
||||||
Map<AbilitySlot, Set<Ability<?>>> BY_SLOT = new EnumMap<>(AbilitySlot.class);
|
Map<AbilitySlot, Set<Ability<?>>> BY_SLOT = new EnumMap<>(AbilitySlot.class);
|
||||||
BiFunction<AbilitySlot, Race, List<Ability<?>>> BY_SLOT_AND_RACE = Util.memoize((slot, race) -> {
|
BiFunction<AbilitySlot, Race.Composite, List<Ability<?>>> BY_SLOT_AND_COMPOSITE_RACE = Util.memoize((slot, race) -> {
|
||||||
return BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>())
|
return BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>())
|
||||||
.stream()
|
.stream()
|
||||||
.filter(a -> a.canUse(race))
|
.filter(a -> race.any(a::canUse))
|
||||||
.toList();
|
.toList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Ability<?>> getAbility(long page) {
|
public Optional<Ability<?>> getAbility(long page) {
|
||||||
List<Ability<?>> found = Abilities.BY_SLOT_AND_RACE.apply(slot, player.getSpecies());
|
List<Ability<?>> found = Abilities.BY_SLOT_AND_COMPOSITE_RACE.apply(slot, player.getCompositeRace());
|
||||||
if (found.isEmpty()) {
|
if (found.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMaxPage() {
|
public long getMaxPage() {
|
||||||
return Abilities.BY_SLOT_AND_RACE.apply(slot, player.getSpecies()).size();
|
return Abilities.BY_SLOT_AND_COMPOSITE_RACE.apply(slot, player.getCompositeRace()).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized Optional<Ability<?>> setActiveAbility(@Nullable Ability<?> power) {
|
protected synchronized Optional<Ability<?>> setActiveAbility(@Nullable Ability<?> power) {
|
||||||
|
@ -249,7 +249,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
||||||
|
|
||||||
protected synchronized Optional<Ability<?>> getActiveAbility() {
|
protected synchronized Optional<Ability<?>> getActiveAbility() {
|
||||||
return activeAbility.filter(ability -> {
|
return activeAbility.filter(ability -> {
|
||||||
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && ability.canUse(player.getSpecies()));
|
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && player.getCompositeRace().any(ability::canUse));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class DismissSpellScreen extends GameGui {
|
||||||
DrawableUtil.drawArc(matrices, 160, 1600, 0, DrawableUtil.TAU, 0x00000020, false);
|
DrawableUtil.drawArc(matrices, 160, 1600, 0, DrawableUtil.TAU, 0x00000020, false);
|
||||||
|
|
||||||
super.render(matrices, mouseX, mouseY, delta);
|
super.render(matrices, mouseX, mouseY, delta);
|
||||||
DrawableUtil.renderRaceIcon(matrices, pony.getSpecies(), 0, 0, 16);
|
DrawableUtil.renderRaceIcon(matrices, pony.getObservedSpecies(), 0, 0, 16);
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
|
|
||||||
DrawableUtil.drawLine(matrices, mouseX, mouseY - 4, mouseX, mouseY + 4, 0xFFAAFF99);
|
DrawableUtil.drawLine(matrices, mouseX, mouseY - 4, mouseX, mouseY + 4, 0xFFAAFF99);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellTyp
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.client.KeyBindingsHandler;
|
import com.minelittlepony.unicopia.client.KeyBindingsHandler;
|
||||||
import com.minelittlepony.unicopia.client.sound.*;
|
import com.minelittlepony.unicopia.client.sound.*;
|
||||||
|
import com.minelittlepony.unicopia.entity.AmuletSelectors;
|
||||||
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
|
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
|
||||||
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
|
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
|
||||||
import com.minelittlepony.unicopia.entity.effect.UEffects;
|
import com.minelittlepony.unicopia.entity.effect.UEffects;
|
||||||
|
@ -125,7 +126,7 @@ public class UHud extends DrawableHelper {
|
||||||
|
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
|
|
||||||
if (pony.getActualSpecies().canCast()) {
|
if (pony.getActualSpecies().canCast() || AmuletSelectors.ALICORN_AMULET.test(pony.getMaster())) {
|
||||||
renderSpell(pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 15 - xDirection * 13, hudY + 3);
|
renderSpell(pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 15 - xDirection * 13, hudY + 3);
|
||||||
renderSpell(pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 15 - xDirection * 2, hudY - 3);
|
renderSpell(pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 15 - xDirection * 2, hudY - 3);
|
||||||
}
|
}
|
||||||
|
@ -217,7 +218,7 @@ public class UHud extends DrawableHelper {
|
||||||
ItemStack glasses = GlassesItem.getForEntity(client.player);
|
ItemStack glasses = GlassesItem.getForEntity(client.player);
|
||||||
boolean hasSunglasses = glasses.getItem() == UItems.SUNGLASSES;
|
boolean hasSunglasses = glasses.getItem() == UItems.SUNGLASSES;
|
||||||
|
|
||||||
if (hasEffect || (!hasSunglasses && pony.getSpecies() == Race.BAT && SunBlindnessStatusEffect.hasSunExposure(client.player))) {
|
if (hasEffect || (!hasSunglasses && pony.getObservedSpecies() == Race.BAT && SunBlindnessStatusEffect.hasSunExposure(client.player))) {
|
||||||
float i = hasEffect ? (client.player.getStatusEffect(UEffects.SUN_BLINDNESS).getDuration() - tickDelta) / SunBlindnessStatusEffect.MAX_DURATION : 0;
|
float i = hasEffect ? (client.player.getStatusEffect(UEffects.SUN_BLINDNESS).getDuration() - tickDelta) / SunBlindnessStatusEffect.MAX_DURATION : 0;
|
||||||
|
|
||||||
float pulse = (1 + (float)Math.sin(client.player.age / 108F)) * 0.25F;
|
float pulse = (1 + (float)Math.sin(client.player.age / 108F)) * 0.25F;
|
||||||
|
|
|
@ -11,10 +11,11 @@ public class ProfileTooltip {
|
||||||
public static Tooltip get(Pony pony) {
|
public static Tooltip get(Pony pony) {
|
||||||
return () -> {
|
return () -> {
|
||||||
return List.of(
|
return List.of(
|
||||||
Text.literal(String.format("Level %d ", pony.getLevel().get() + 1)).append(pony.getSpecies().getDisplayName()).formatted(pony.getSpecies().getAffinity().getColor()),
|
Text.literal(String.format("Level %d ", pony.getLevel().get() + 1)).append(pony.getActualSpecies().getDisplayName()).formatted(pony.getSpecies().getAffinity().getColor()),
|
||||||
Text.literal(String.format("Mana: %d%%", (int)(pony.getMagicalReserves().getMana().getPercentFill() * 100))),
|
Text.literal(String.format("Mana: %d%%", (int)(pony.getMagicalReserves().getMana().getPercentFill() * 100))),
|
||||||
|
Text.literal(String.format("Corruption: %d%%", (int)(pony.getCorruption().getScaled(100)))),
|
||||||
Text.literal(String.format("Experience: %d", (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100))),
|
Text.literal(String.format("Experience: %d", (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100))),
|
||||||
Text.literal(String.format("Next level in: %d experience points", 100 - (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100)))
|
Text.literal(String.format("Next level in: %dxp", 100 - (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100)))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,15 @@ public class SpellbookProfilePageContent extends DrawableHelper implements Spell
|
||||||
|
|
||||||
screen.addDrawable(new SpellbookScreen.ImageButton(x, y, size, size))
|
screen.addDrawable(new SpellbookScreen.ImageButton(x, y, size, size))
|
||||||
.getStyle()
|
.getStyle()
|
||||||
.setIcon(TribeButton.createSprite(pony.getSpecies(), 0, 0, size))
|
.setIcon(TribeButton.createSprite(pony.getActualSpecies(), 0, 0, size))
|
||||||
.setTooltip(ProfileTooltip.get(pony));
|
.setTooltip(ProfileTooltip.get(pony));
|
||||||
|
|
||||||
|
if (pony.getSpecies() != pony.getActualSpecies()) {
|
||||||
|
int halfSize = size / 2;
|
||||||
|
screen.addDrawable(new SpellbookScreen.ImageButton(x + halfSize, y + halfSize, halfSize, halfSize))
|
||||||
|
.getStyle()
|
||||||
|
.setIcon(TribeButton.createSprite(pony.getSpecies(), 0, 0, halfSize));
|
||||||
|
}
|
||||||
|
|
||||||
float mainAngle = 90 * MathHelper.RADIANS_PER_DEGREE;
|
float mainAngle = 90 * MathHelper.RADIANS_PER_DEGREE;
|
||||||
float offAngle = 60 * MathHelper.RADIANS_PER_DEGREE;
|
float offAngle = 60 * MathHelper.RADIANS_PER_DEGREE;
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class SunBlindnessStatusEffect extends StatusEffect {
|
||||||
public static boolean isSunImmune(LivingEntity entity) {
|
public static boolean isSunImmune(LivingEntity entity) {
|
||||||
return entity.hasStatusEffect(StatusEffects.BLINDNESS)
|
return entity.hasStatusEffect(StatusEffects.BLINDNESS)
|
||||||
|| entity.hasPortalCooldown()
|
|| entity.hasPortalCooldown()
|
||||||
|| Pony.of(entity).map(pony -> pony.isSunImmune()).orElse(false);
|
|| Pony.of(entity).filter(Pony::isSunImmune).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasSunExposure(LivingEntity entity) {
|
public static boolean hasSunExposure(LivingEntity entity) {
|
||||||
|
|
|
@ -218,7 +218,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
||||||
if ((entity.isOnGround() && entity.isSneaking())
|
if ((entity.isOnGround() && entity.isSneaking())
|
||||||
|| entity.isTouchingWater()
|
|| entity.isTouchingWater()
|
||||||
|| entity.horizontalCollision
|
|| entity.horizontalCollision
|
||||||
|| (entity.verticalCollision && (pony.getSpecies() != Race.BAT || velocity.y < 0))) {
|
|| (entity.verticalCollision && (pony.getObservedSpecies() != Race.BAT || velocity.y < 0))) {
|
||||||
|
|
||||||
if (entity.getAbilities().flying && entity.horizontalCollision) {
|
if (entity.getAbilities().flying && entity.horizontalCollision) {
|
||||||
handleWallCollission(velocity);
|
handleWallCollission(velocity);
|
||||||
|
@ -251,7 +251,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
||||||
|
|
||||||
if (type.canFly()) {
|
if (type.canFly()) {
|
||||||
if (isFlying()) {
|
if (isFlying()) {
|
||||||
if (pony.getSpecies() == Race.BAT && entity.verticalCollision && pony.canHangAt(pony.getOrigin().up(2))) {
|
if (pony.getObservedSpecies() == Race.BAT && entity.verticalCollision && pony.canHangAt(pony.getOrigin().up(2))) {
|
||||||
EntityAttributeInstance attr = entity.getAttributeInstance(UEntityAttributes.ENTITY_GRAVTY_MODIFIER);
|
EntityAttributeInstance attr = entity.getAttributeInstance(UEntityAttributes.ENTITY_GRAVTY_MODIFIER);
|
||||||
|
|
||||||
if (!attr.hasModifier(PlayerAttributes.BAT_HANGING)) {
|
if (!attr.hasModifier(PlayerAttributes.BAT_HANGING)) {
|
||||||
|
@ -327,7 +327,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
||||||
if (type.isAvian()) {
|
if (type.isAvian()) {
|
||||||
applyThrust(velocity);
|
applyThrust(velocity);
|
||||||
|
|
||||||
if (pony.getSpecies() != Race.BAT && entity.world.random.nextInt(9000) == 0) {
|
if (pony.getObservedSpecies() != Race.BAT && entity.world.random.nextInt(9000) == 0) {
|
||||||
entity.dropItem(UItems.PEGASUS_FEATHER);
|
entity.dropItem(UItems.PEGASUS_FEATHER);
|
||||||
entity.playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1);
|
entity.playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1);
|
||||||
UCriteria.SHED_FEATHER.trigger(entity);
|
UCriteria.SHED_FEATHER.trigger(entity);
|
||||||
|
|
|
@ -181,6 +181,11 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
.orElse(getActualSpecies());
|
.orElse(getActualSpecies());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Race.Composite getCompositeRace() {
|
||||||
|
Race observed = getObservedSpecies();
|
||||||
|
return new Race.Composite(observed, AmuletSelectors.ALICORN_AMULET.test(entity) ? Race.ALICORN : observed);
|
||||||
|
}
|
||||||
|
|
||||||
public Race getActualSpecies() {
|
public Race getActualSpecies() {
|
||||||
return Race.fromName(entity.getDataTracker().get(RACE), Race.HUMAN);
|
return Race.fromName(entity.getDataTracker().get(RACE), Race.HUMAN);
|
||||||
}
|
}
|
||||||
|
@ -287,7 +292,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
|
|
||||||
public void onSpawn() {
|
public void onSpawn() {
|
||||||
if (entity.world instanceof ServerWorld sw
|
if (entity.world instanceof ServerWorld sw
|
||||||
&& getSpecies() == Race.BAT
|
&& getObservedSpecies() == Race.BAT
|
||||||
&& sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE
|
&& sw.getServer().getSaveProperties().getGameMode() != GameMode.ADVENTURE
|
||||||
&& SunBlindnessStatusEffect.isPositionExposedToSun(sw, getOrigin())) {
|
&& SunBlindnessStatusEffect.isPositionExposedToSun(sw, getOrigin())) {
|
||||||
SpawnLocator.selectSpawnPosition(sw, entity);
|
SpawnLocator.selectSpawnPosition(sw, entity);
|
||||||
|
@ -371,14 +376,14 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
|
||||||
|
|
||||||
if (isHanging()) {
|
if (isHanging()) {
|
||||||
((LivingEntityDuck)entity).setLeaningPitch(0);
|
((LivingEntityDuck)entity).setLeaningPitch(0);
|
||||||
if (!isClient() && (getSpecies() != Race.BAT || (ticksHanging++ > 2 && hangingPosition.filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty()))) {
|
if (!isClient() && (getObservedSpecies() != Race.BAT || (ticksHanging++ > 2 && hangingPosition.filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty()))) {
|
||||||
stopHanging();
|
stopHanging();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ticksHanging = 0;
|
ticksHanging = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getSpecies() == Race.BAT && !entity.hasPortalCooldown()) {
|
if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) {
|
||||||
if (SunBlindnessStatusEffect.hasSunExposure(entity)) {
|
if (SunBlindnessStatusEffect.hasSunExposure(entity)) {
|
||||||
if (ticksInSun < 200) {
|
if (ticksInSun < 200) {
|
||||||
ticksInSun++;
|
ticksInSun++;
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class RacePredicatedAliasedBlockItem extends AliasedBlockItem {
|
||||||
@Override
|
@Override
|
||||||
public ActionResult useOnBlock(ItemUsageContext context) {
|
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||||
Pony pony = Pony.of(context.getPlayer());
|
Pony pony = Pony.of(context.getPlayer());
|
||||||
if (pony == null || !predicate.test(pony.getSpecies())) {
|
if (pony == null || !predicate.test(pony.getObservedSpecies())) {
|
||||||
return ActionResult.FAIL;
|
return ActionResult.FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ public record Ailment (
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||||
if (!Pony.of(player).getSpecies().hasIronGut()) {
|
if (!Pony.of(player).getObservedSpecies().hasIronGut()) {
|
||||||
return TypedActionResult.fail(player.getStackInHand(hand));
|
return TypedActionResult.fail(player.getStackInHand(hand));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -52,7 +52,7 @@ public record Ailment (
|
||||||
if (map.isEmpty()) {
|
if (map.isEmpty()) {
|
||||||
return of(def);
|
return of(def);
|
||||||
}
|
}
|
||||||
return entity -> Optional.of(entity instanceof PlayerEntity player ? map.getOrDefault(Pony.of(player).getSpecies(), def) : def);
|
return entity -> Optional.of(entity instanceof PlayerEntity player ? map.getOrDefault(Pony.of(player).getObservedSpecies(), def) : def);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ailment.Set of(Ailment ailment) {
|
static Ailment.Set of(Ailment ailment) {
|
||||||
|
|
Loading…
Reference in a new issue