Make the seapony transformation into an ability granted if you're wearing the necklace

This commit is contained in:
Sollace 2023-11-09 16:26:26 +00:00
parent 5dbff11d7a
commit e0826bf1e3
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 148 additions and 11 deletions

View file

@ -27,6 +27,7 @@ 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 (Supplier<Composite> compositeSupplier, Availability availability, boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) 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 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("race.unknown", id));
@ -35,11 +36,15 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
} }
public static Race register(Identifier id, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) { public static Race register(Identifier id, Availability availability, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) {
return Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null)), availability, magic, flight, earth, nocturnal, canHang)); Race race = Registry.register(REGISTRY, id, new Race(Suppliers.memoize(() -> new Composite(REGISTRY.get(id), null, null)), availability, magic, flight, earth, nocturnal, canHang));
if (availability.isGrantable()) {
Registry.register(COMMAND_REGISTRY, id, race);
}
return race;
} }
public static RegistryKeyArgumentType<Race> argument() { public static RegistryKeyArgumentType<Race> argument() {
return RegistryKeyArgumentType.registryKey(REGISTRY_KEY); return RegistryKeyArgumentType.registryKey(COMMAND_REGISTRY.getKey());
} }
/** /**
@ -64,8 +69,8 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return compositeSupplier.get(); return compositeSupplier.get();
} }
public Composite composite(@Nullable Race pseudo) { public Composite composite(@Nullable Race pseudo, @Nullable Race potential) {
return pseudo == null ? composite() : new Composite(this, pseudo); return pseudo == null && potential == null ? composite() : new Composite(this, pseudo, potential);
} }
@Override @Override
@ -147,6 +152,10 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return this; return this;
} }
public Race or(Race other) {
return isEquine() ? this : other;
}
@Override @Override
public int hashCode() { public int hashCode() {
return getId().hashCode(); return getId().hashCode();
@ -194,7 +203,7 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
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, @Nullable Race pseudo) { public record Composite (Race physical, @Nullable Race pseudo, @Nullable Race potential) {
public Race collapsed() { public Race collapsed() {
return pseudo == null ? physical : pseudo; return pseudo == null ? physical : pseudo;
} }

View file

@ -24,6 +24,9 @@ public interface Abilities {
.toList(); .toList();
}); });
// all races
Ability<?> CHANGE_FORM = register(new ChangeFormAbility(), "change_form", AbilitySlot.PRIMARY);
// unicorn / alicorn // unicorn / alicorn
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY); Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
Ability<?> SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.PRIMARY); Ability<?> SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.PRIMARY);

View file

@ -179,6 +179,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
return; return;
} }
if (cooldown > 100 && player.asEntity().isCreative()) {
cooldown = Math.max(10, cooldown - 100);
}
if (cooldown > 0 && cooldown-- > 0) { if (cooldown > 0 && cooldown-- > 0) {
ability.coolDown(player, slot); ability.coolDown(player, slot);

View file

@ -0,0 +1,99 @@
package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
public class ChangeFormAbility implements Ability<Hit> {
@Override
public int getWarmupTime(Pony player) {
return 10;
}
@Override
public int getCooldownTime(Pony player) {
return 1000;
}
@Override
public boolean canUse(Race.Composite race) {
return race.potential() != null;
}
@Override
public boolean canUse(Race race) {
return true;
}
@Override
public Identifier getIcon(Pony player) {
Race potential = player.getCompositeRace().potential();
if (potential == null) {
return Ability.super.getIcon(player);
}
return getId().withPath(p -> "textures/gui/ability/" + p + "_" + potential.getId().getPath() + ".png");
}
@Nullable
@Override
public Optional<Hit> prepare(Pony player) {
return Hit.of(canUse(player.getCompositeRace()));
}
@Override
public Hit.Serializer<Hit> getSerializer() {
return Hit.SERIALIZER;
}
@Override
public double getCostEstimate(Pony player) {
return 5;
}
@Override
public boolean apply(Pony player, Hit data) {
if (prepare(player).isEmpty()) {
return false;
}
player.subtractEnergyCost(5);
Race.Composite composite = player.getCompositeRace();
Race actualRace = player.getSpecies();
player.setSpecies(composite.potential());
player.setSuppressedRace(actualRace.availability().isGrantable() ? actualRace : Race.UNSET);
return true;
}
@Override
public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().addPercent(6);
if (player.getAbilities().getStat(slot).getWarmup() % 5 == 0) {
player.asWorld().playSound(null, player.getOrigin(), SoundEvents.BLOCK_BUBBLE_COLUMN_WHIRLPOOL_INSIDE, SoundCategory.PLAYERS);
}
if (player.asWorld().random.nextInt(5) == 0) {
player.asWorld().playSound(null, player.getOrigin(), USounds.Vanilla.BLOCK_BUBBLE_COLUMN_BUBBLE_POP, SoundCategory.PLAYERS);
}
player.spawnParticles(ParticleTypes.BUBBLE_COLUMN_UP, 15);
player.spawnParticles(ParticleTypes.BUBBLE_POP, 15);
}
@Override
public void coolDown(Pony player, AbilitySlot slot) {
}
}

View file

@ -60,8 +60,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
@Override @Override
public Identifier getIcon(Pony player) { public Identifier getIcon(Pony player) {
Identifier id = Abilities.REGISTRY.getId(this); return getId().withPath(p -> "textures/gui/ability/" + p
return new Identifier(id.getNamespace(), "textures/gui/ability/" + id.getPath()
+ "_" + player.getObservedSpecies().getId().getPath() + "_" + player.getObservedSpecies().getId().getPath()
+ "_" + (getKickDirection(player) > 0 ? "forward" : "backward") + "_" + (getKickDirection(player) > 0 ? "forward" : "backward")
+ ".png"); + ".png");

View file

@ -66,6 +66,7 @@ import net.minecraft.world.GameRules;
public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, UpdateCallback { public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, UpdateCallback {
private static final TrackedData<String> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); private static final TrackedData<String> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
private static final TrackedData<String> SUPPRESSED_RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
static final TrackedData<Float> ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); static final TrackedData<Float> ENERGY = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); static final TrackedData<Float> EXHAUSTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
@ -120,6 +121,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
this.mana = addTicker(new ManaContainer(this)); this.mana = addTicker(new ManaContainer(this));
player.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); player.getDataTracker().startTracking(RACE, Race.DEFAULT_ID);
player.getDataTracker().startTracking(SUPPRESSED_RACE, Race.DEFAULT_ID);
addTicker(this::updateAnimations); addTicker(this::updateAnimations);
addTicker(this::updateBatPonyAbilities); addTicker(this::updateBatPonyAbilities);
@ -223,8 +225,13 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void setSpecies(Race race) { public void setSpecies(Race race) {
race = race.validate(entity); race = race.validate(entity);
Race current = getSpecies();
entity.getDataTracker().set(RACE, Race.REGISTRY.getId(race.validate(entity)).toString());
if (race != current) {
clearSuppressedRace();
}
ticksInSun = 0; ticksInSun = 0;
entity.getDataTracker().set(RACE, Race.REGISTRY.getId(race).toString());
gravity.updateFlightState(); gravity.updateFlightState();
entity.sendAbilitiesUpdate(); entity.sendAbilitiesUpdate();
@ -232,6 +239,18 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
UCriteria.PLAYER_CHANGE_RACE.trigger(entity); UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
} }
public void setSuppressedRace(Race race) {
entity.getDataTracker().set(SUPPRESSED_RACE, Race.REGISTRY.getId(race.validate(entity)).toString());
}
public void clearSuppressedRace() {
setSuppressedRace(Race.UNSET);
}
private Race getSuppressedRace() {
return Race.fromName(entity.getDataTracker().get(SUPPRESSED_RACE), Race.UNSET);
}
public TraitDiscovery getDiscoveries() { public TraitDiscovery getDiscoveries() {
return discoveries; return discoveries;
} }
@ -354,17 +373,19 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public boolean beforeUpdate() { public boolean beforeUpdate() {
if (compositeRace.includes(Race.UNSET) || entity.age % 2 == 0) { if (compositeRace.includes(Race.UNSET) || entity.age % 2 == 0) {
Race intrinsicRace = getSpecies();
Race suppressedRace = getSuppressedRace();
compositeRace = getSpellSlot() compositeRace = getSpellSlot()
.get(SpellPredicate.IS_MIMIC, true) .get(SpellPredicate.IS_MIMIC, true)
.map(AbstractDisguiseSpell::getDisguise) .map(AbstractDisguiseSpell::getDisguise)
.map(EntityAppearance::getAppearance) .map(EntityAppearance::getAppearance)
.flatMap(Pony::of) .flatMap(Pony::of)
.map(Pony::getSpecies) .map(Pony::getSpecies)
.orElseGet(this::getSpecies).composite( .orElse(intrinsicRace).composite(
AmuletSelectors.UNICORN_AMULET.test(entity) ? Race.UNICORN AmuletSelectors.UNICORN_AMULET.test(entity) ? Race.UNICORN
: AmuletSelectors.ALICORN_AMULET.test(entity) ? Race.ALICORN : AmuletSelectors.ALICORN_AMULET.test(entity) ? Race.ALICORN
: AmuletSelectors.PEARL_NECKLACE.test(entity) ? Race.SEAPONY : null,
: null AmuletSelectors.PEARL_NECKLACE.test(entity) ? suppressedRace.or(Race.SEAPONY) : null
); );
} }
@ -794,6 +815,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
public void toSyncronisedNbt(NbtCompound compound) { public void toSyncronisedNbt(NbtCompound compound) {
super.toSyncronisedNbt(compound); super.toSyncronisedNbt(compound);
compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString());
compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString());
compound.putFloat("magicExhaustion", magicExhaustion); compound.putFloat("magicExhaustion", magicExhaustion);
compound.putInt("ticksInSun", ticksInSun); compound.putInt("ticksInSun", ticksInSun);
compound.putBoolean("hasShades", hasShades); compound.putBoolean("hasShades", hasShades);
@ -819,6 +841,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
public void fromSynchronizedNbt(NbtCompound compound) { public void fromSynchronizedNbt(NbtCompound compound) {
super.fromSynchronizedNbt(compound); super.fromSynchronizedNbt(compound);
setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN));
setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET));
powers.fromNBT(compound.getCompound("powers")); powers.fromNBT(compound.getCompound("powers"));
gravity.fromNBT(compound.getCompound("gravity")); gravity.fromNBT(compound.getCompound("gravity"));
charms.fromNBT(compound.getCompound("charms")); charms.fromNBT(compound.getCompound("charms"));