Implement bat wings and unicorn horns for ponies that don't normally have them but are those races in the mod

This commit is contained in:
Sollace 2023-08-16 19:42:31 +01:00
parent 49e74f4c54
commit 5ec332a165
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
5 changed files with 149 additions and 120 deletions

View file

@ -59,9 +59,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
@Override
public double getCostEstimate(Pony player) {
double distance = MineLPDelegate.getInstance().getPlayerPonyRace(player.asEntity()).isHuman() ? 6 : -6;
return TraceHelper.findBlock(player.asEntity(), distance, 1)
return TraceHelper.findBlock(player.asEntity(), getKickDirection(player) * 6, 1)
.filter(pos -> TreeType.at(pos, player.asWorld()) != TreeType.NONE)
.isPresent() ? 3 : 1;
}
@ -121,7 +119,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
}
private int getKickDirection(Pony player) {
return MineLPDelegate.getInstance().getPlayerPonyRace(player.asEntity()).isHuman() ? 1 : -1;
return MineLPDelegate.getInstance().getPlayerPonyRace(player.asEntity()).isEquine() ? -1 : 1;
}
private Pos getDefaultKickLocation(Pony player) {

View file

@ -38,7 +38,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Nullable
@Override
public Optional<Hit> prepare(Pony player) {
return Hit.of(player.canUseSuperMove() && player.getPhysics().isFlying() && !SpellType.RAINBOOM.isOn(player));
return Hit.of(player.canUseSuperMove() && player.getPhysics().isFlying() && !player.getMotion().isRainbooming());
}
@Override
@ -54,7 +54,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Override
public boolean onQuickAction(Pony player, ActivationType type, Optional<Hit> data) {
if (type == ActivationType.TAP && player.getPhysics().isFlying() && player.getMagicalReserves().getMana().get() > 40) {
if (type == ActivationType.TAP && !player.getMotion().isRainbooming() && player.getPhysics().isFlying() && player.getMagicalReserves().getMana().get() > 40) {
player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(2.5F, 0.3F));
player.subtractEnergyCost(4);
player.getMagicalReserves().getCharge().add(2);

View file

@ -0,0 +1,133 @@
package com.minelittlepony.unicopia.client.minelittlepony;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.gear.IGear;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.PlayerModelKey;
import com.minelittlepony.client.model.entity.race.PegasusModel;
import com.minelittlepony.client.model.entity.race.UnicornModel;
import com.minelittlepony.client.model.part.UnicornHorn;
import com.minelittlepony.mson.api.MsonModel;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.AmuletSelectors;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
class BodyPartGear<M extends ClientPonyModel<LivingEntity> & MsonModel & IModel> implements IGear {
private static final Identifier ICARUS_WINGS = Unicopia.id("textures/models/wings/icarus_pony.png");
private static final Identifier ICARUS_WINGS_CORRUPTED = Unicopia.id("textures/models/wings/icarus_corrupted_pony.png");
public static final Predicate<LivingEntity> BAT_WINGS_PREDICATE = AmuletSelectors.PEGASUS_AMULET.negate().and(EquinePredicates.PLAYER_BAT);
public static final Identifier BAT_WINGS = Unicopia.id("textures/models/wings/bat_pony.png");
public static final Predicate<LivingEntity> UNICORN_HORN_PREDICATE = AmuletSelectors.ALICORN_AMULET.or(EquinePredicates.raceMatches(Race::canCast));
public static final Identifier UNICORN_HORN = Unicopia.id("textures/models/horn/unicorn.png");
public static final Predicate<LivingEntity> PEGA_WINGS_PREDICATE = AmuletSelectors.PEGASUS_AMULET.or(EquinePredicates.raceMatches(Race::canInteractWithClouds));
public static final Identifier PEGASUS_WINGS = Unicopia.id("textures/models/wings/pegasus_pony.png");
public static BodyPartGear<WingsGearModel> pegasusWings() {
return new BodyPartGear<>(BodyPart.BODY, ModelType.PEGASUS, PEGA_WINGS_PREDICATE, WingsGearModel::new, WingsGearModel::getWings, e -> {
if (AmuletSelectors.PEGASUS_AMULET.test((LivingEntity)e)) {
return e.getWorld().getDimension().ultrawarm() ? ICARUS_WINGS_CORRUPTED : ICARUS_WINGS;
}
return PEGASUS_WINGS;
});
}
public static BodyPartGear<WingsGearModel> batWings() {
return new BodyPartGear<>(BodyPart.BODY, ModelType.BAT_PONY, BAT_WINGS_PREDICATE, WingsGearModel::new, WingsGearModel::getWings, e -> BAT_WINGS);
}
public static BodyPartGear<HornGearModel> unicornHorn() {
return new BodyPartGear<>(BodyPart.HEAD, ModelType.UNICORN, UNICORN_HORN_PREDICATE, HornGearModel::new, HornGearModel::getHorn, e -> UNICORN_HORN);
}
private final M model;
private final Predicate<LivingEntity> renderTargetPredicate;
private final IPart part;
private final Function<Entity, Identifier> textureSupplier;
private final BodyPart gearLocation;
public BodyPartGear(
BodyPart gearLocation,
PlayerModelKey<LivingEntity, ? super M> modelKey,
Predicate<LivingEntity> renderTargetPredicate,
MsonModel.Factory<M> modelFactory,
Function<M, IPart> partExtractor,
Function<Entity, Identifier> textureSupplier) {
this.gearLocation = gearLocation;
this.model = modelKey.steveKey().createModel(modelFactory);
this.part = partExtractor.apply(this.model);
this.renderTargetPredicate = renderTargetPredicate;
this.textureSupplier = textureSupplier;
}
@Override
public BodyPart getGearLocation() {
return gearLocation;
}
@Override
public boolean canRender(IModel model, Entity entity) {
return entity instanceof LivingEntity l
&& MineLPDelegate.getInstance().getRace(entity).isEquine()
&& !MineLPDelegate.getInstance().getRace(entity).canFly()
&& renderTargetPredicate.test(l);
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return textureSupplier.apply(entity);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
((ClientPonyModel)model).copyAttributes(this.model);
part.setPartAngles(this.model.getAttributes(), move, swing, bodySwing, ticks);
}
@Override
public void render(MatrixStack stack, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha, UUID interpolatorId) {
part.renderPart(stack, consumer, light, overlay, red, green, blue, alpha, model.getAttributes());
}
static final class WingsGearModel extends PegasusModel<LivingEntity> {
public WingsGearModel(ModelPart tree) {
super(tree, false);
}
@Override
public boolean canFly() {
return true;
}
}
static final class HornGearModel extends UnicornModel<LivingEntity> {
public HornGearModel(ModelPart tree) {
super(tree, false);
}
@Override
public boolean canFly() {
return true;
}
public UnicornHorn getHorn() {
return horn;
}
}
}

View file

@ -27,7 +27,9 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
IGear.register(() -> new BangleGear(TrinketsDelegate.MAINHAND));
IGear.register(() -> new BangleGear(TrinketsDelegate.OFFHAND));
IGear.register(HeldEntityGear::new);
IGear.register(WingsGear::new);
IGear.register(BodyPartGear::pegasusWings);
IGear.register(BodyPartGear::batWings);
IGear.register(BodyPartGear::unicornHorn);
IGear.register(AmuletGear::new);
IGear.register(GlassesGear::new);
}
@ -80,27 +82,14 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
}
private static Race toUnicopiaRace(com.minelittlepony.api.pony.meta.Race race) {
switch (race) {
case ALICORN:
return Race.ALICORN;
case CHANGELING:
case CHANGEDLING:
return Race.CHANGELING;
case ZEBRA:
case EARTH:
return Race.EARTH;
case GRYPHON:
case HIPPOGRIFF:
case PEGASUS:
return Race.PEGASUS;
case BATPONY:
return Race.BAT;
case SEAPONY:
case UNICORN:
case KIRIN:
return Race.UNICORN;
default:
return Race.HUMAN;
}
return switch (race) {
case ALICORN -> Race.ALICORN;
case CHANGELING, CHANGEDLING -> Race.CHANGELING;
case ZEBRA, EARTH -> Race.EARTH;
case GRYPHON, HIPPOGRIFF, PEGASUS -> Race.PEGASUS;
case BATPONY -> Race.BAT;
case SEAPONY, UNICORN, KIRIN -> Race.UNICORN;
default -> Race.HUMAN;
};
}
}

View file

@ -1,91 +0,0 @@
package com.minelittlepony.unicopia.client.minelittlepony;
import java.util.UUID;
import com.minelittlepony.api.model.*;
import com.minelittlepony.api.model.gear.IGear;
import com.minelittlepony.api.pony.*;
import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.model.ModelType;
import com.minelittlepony.client.model.entity.race.PegasusModel;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.*;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
class WingsGear implements IGear {
private static final Identifier ICARUS_WINGS = Unicopia.id("textures/models/wings/icarus_pony.png");
private static final Identifier ICARUS_WINGS_CORRUPTED = Unicopia.id("textures/models/wings/icarus_corrupted_pony.png");
private static final Identifier PEGASUS_WINGS = Unicopia.id("textures/models/wings/pegasus_pony.png");
private static final Identifier BAT_WINGS = Unicopia.id("textures/models/wings/bat_pony.png");
private final Model model = ModelType.PEGASUS.steveKey().createModel(Model::new);
@Override
public boolean canRender(IModel model, Entity entity) {
return entity instanceof LivingEntity l
&& !MineLPDelegate.getInstance().getRace(entity).canFly()
&& (AmuletSelectors.PEGASUS_AMULET.test(l) || Equine.of(entity).filter(this::canRender).isPresent());
}
protected boolean canRender(Equine<?> equine) {
if (equine instanceof Pony pony) {
return pony.getObservedSpecies().canInteractWithClouds();
}
return equine.getSpecies().canFly();
}
@Override
public BodyPart getGearLocation() {
return BodyPart.BODY;
}
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
Living<?> living = Living.living(entity);
if (living == null) {
return DefaultPonySkinHelper.STEVE;
}
if (AmuletSelectors.PEGASUS_AMULET.test(living.asEntity())) {
return entity.getWorld().getDimension().ultrawarm() ? ICARUS_WINGS_CORRUPTED : ICARUS_WINGS;
}
Race race = living instanceof Pony pony ? pony.getObservedSpecies() : living.getSpecies();
if (race.canInteractWithClouds()) {
return PEGASUS_WINGS;
}
return BAT_WINGS;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
((ClientPonyModel)model).copyAttributes(this.model);
this.model.getWings().setPartAngles(this.model.getAttributes(), move, swing, bodySwing, ticks);
}
@Override
public void render(MatrixStack stack, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha, UUID interpolatorId) {
model.getWings().renderPart(stack, consumer, light, overlay, red, green, blue, alpha, model.getAttributes());
}
static class Model extends PegasusModel<LivingEntity> {
public Model(ModelPart tree) {
super(tree, false);
}
@Override
public boolean canFly() {
return true;
}
}
}