mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Ponies that cast magic now have horns
This commit is contained in:
parent
a444395c28
commit
f3d251c1d0
9 changed files with 160 additions and 4 deletions
|
@ -28,6 +28,10 @@ public interface Ability<T extends Hit> {
|
||||||
*/
|
*/
|
||||||
int getCooldownTime(Pony player);
|
int getCooldownTime(Pony player);
|
||||||
|
|
||||||
|
default int getColor(Pony player) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -64,6 +64,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
||||||
return stats.values();
|
return stats.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Stat> getActiveStat() {
|
||||||
|
return stats.values().stream().filter(stat -> stat.getFillProgress() > 0).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
public Stat getStat(AbilitySlot slot) {
|
public Stat getStat(AbilitySlot slot) {
|
||||||
return stats.computeIfAbsent(slot, Stat::new);
|
return stats.computeIfAbsent(slot, Stat::new);
|
||||||
}
|
}
|
||||||
|
@ -246,7 +250,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized Optional<Ability<?>> getActiveAbility() {
|
public synchronized Optional<Ability<?>> getActiveAbility() {
|
||||||
return activeAbility.filter(ability -> {
|
return activeAbility.filter(ability -> {
|
||||||
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && player.getCompositeRace().any(ability::canUse));
|
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && player.getCompositeRace().any(ability::canUse));
|
||||||
});
|
});
|
||||||
|
|
|
@ -80,6 +80,22 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
return !spell.getResult().isAccepted() || spell.getValue().isOn(player) ? 2 : 4;
|
return !spell.getResult().isAccepted() || spell.getValue().isOn(player) ? 2 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColor(Pony player) {
|
||||||
|
TypedActionResult<ItemStack> amulet = getAmulet(player);
|
||||||
|
if (amulet.getResult().isAccepted()) {
|
||||||
|
return 0x000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hand hand = player.asEntity().isSneaking() ? Hand.OFF_HAND : Hand.MAIN_HAND;
|
||||||
|
TypedActionResult<CustomisedSpellType<?>> newSpell = player.getCharms().getSpellInHand(hand);
|
||||||
|
|
||||||
|
if (newSpell.getResult() != ActionResult.FAIL) {
|
||||||
|
return newSpell.getValue().type().getColor();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Pony player, Hit data) {
|
public void apply(Pony player, Hit data) {
|
||||||
if (!player.canCast()) {
|
if (!player.canCast()) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.ability.data.Pos;
|
import com.minelittlepony.unicopia.ability.data.Pos;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
@ -36,6 +37,11 @@ public class UnicornDispellAbility implements Ability<Pos> {
|
||||||
return race.canCast() || race == Race.CHANGELING;
|
return race.canCast() || race == Race.CHANGELING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColor(Pony player) {
|
||||||
|
return SpellType.PORTAL.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Identifier getIcon(Pony player, boolean swap) {
|
public Identifier getIcon(Pony player, boolean swap) {
|
||||||
Identifier id = Abilities.REGISTRY.getId(this);
|
Identifier id = Abilities.REGISTRY.getId(this);
|
||||||
|
|
|
@ -5,6 +5,7 @@ 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;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
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.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
@ -60,6 +61,11 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
return pos.distanceTo(player) / 10;
|
return pos.distanceTo(player) / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColor(Pony player) {
|
||||||
|
return SpellType.PORTAL.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pos tryActivate(Pony player) {
|
public Pos tryActivate(Pony player) {
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,22 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
|
||||||
SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;
|
SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;
|
||||||
SpellPredicate<TimedSpell> IS_TIMED = spell -> spell instanceof TimedSpell;
|
SpellPredicate<TimedSpell> IS_TIMED = spell -> spell instanceof TimedSpell;
|
||||||
|
|
||||||
|
SpellPredicate<?> IS_NOT_PLACED = IS_PLACED.negate();
|
||||||
|
|
||||||
default <Q extends Spell> SpellPredicate<Q> and(SpellPredicate<Q> predicate) {
|
default <Q extends Spell> SpellPredicate<Q> and(SpellPredicate<Q> predicate) {
|
||||||
SpellPredicate<T> self = this;
|
SpellPredicate<T> self = this;
|
||||||
return s -> {
|
return s -> self.test(s) && predicate.test(s);
|
||||||
return self.test(s) && predicate.test(s);
|
}
|
||||||
};
|
|
||||||
|
default <Q extends Spell> SpellPredicate<? extends Spell> or(SpellPredicate<Q> predicate) {
|
||||||
|
SpellPredicate<T> self = this;
|
||||||
|
return s -> self.test(s) || predicate.test(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default SpellPredicate<?> negate() {
|
||||||
|
SpellPredicate<T> self = this;
|
||||||
|
return s -> !self.test(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isOn(Caster<?> caster) {
|
default boolean isOn(Caster<?> caster) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ public interface URenderers {
|
||||||
AccessoryFeatureRenderer.register(BraceletFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(BraceletFeatureRenderer::new);
|
||||||
AccessoryFeatureRenderer.register(AmuletFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(AmuletFeatureRenderer::new);
|
||||||
AccessoryFeatureRenderer.register(WingsFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(WingsFeatureRenderer::new);
|
||||||
|
AccessoryFeatureRenderer.register(HornFeatureRenderer::new);
|
||||||
AccessoryFeatureRenderer.register(IcarusWingsFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(IcarusWingsFeatureRenderer::new);
|
||||||
AccessoryFeatureRenderer.register(BatWingsFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(BatWingsFeatureRenderer::new);
|
||||||
AccessoryFeatureRenderer.register(GlassesFeatureRenderer::new);
|
AccessoryFeatureRenderer.register(GlassesFeatureRenderer::new);
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
package com.minelittlepony.unicopia.client.render;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.ability.AbilityDispatcher.Stat;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||||
|
|
||||||
|
import net.minecraft.client.model.Dilation;
|
||||||
|
import net.minecraft.client.model.Model;
|
||||||
|
import net.minecraft.client.model.ModelData;
|
||||||
|
import net.minecraft.client.model.ModelPart;
|
||||||
|
import net.minecraft.client.model.ModelPartBuilder;
|
||||||
|
import net.minecraft.client.model.ModelPartData;
|
||||||
|
import net.minecraft.client.model.ModelTransform;
|
||||||
|
import net.minecraft.client.model.TexturedModelData;
|
||||||
|
import net.minecraft.client.render.OverlayTexture;
|
||||||
|
import net.minecraft.client.render.RenderLayer;
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||||
|
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||||
|
import net.minecraft.client.render.entity.model.EntityModelPartNames;
|
||||||
|
import net.minecraft.client.render.item.ItemRenderer;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.util.*;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
public class HornFeatureRenderer<E extends LivingEntity> implements AccessoryFeatureRenderer.Feature<E> {
|
||||||
|
|
||||||
|
public static final Identifier TEXTURE = Unicopia.id("textures/models/horn/unicorn.png");
|
||||||
|
|
||||||
|
private final HornModel model;
|
||||||
|
|
||||||
|
private final FeatureRendererContext<E, ? extends BipedEntityModel<E>> context;
|
||||||
|
|
||||||
|
public HornFeatureRenderer(FeatureRendererContext<E, ? extends BipedEntityModel<E>> context) {
|
||||||
|
this.context = context;
|
||||||
|
model = new HornModel(HornModel.getData(Dilation.NONE).createModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canRender(E entity) {
|
||||||
|
return entity instanceof PlayerEntity player && Pony.of(player).getObservedSpecies().canCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) {
|
||||||
|
if (canRender(entity)) {
|
||||||
|
model.setAngles(context.getModel());
|
||||||
|
model.setState(false);
|
||||||
|
model.render(stack, ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(TEXTURE), false, false), lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
Pony.of(entity).flatMap(pony -> {
|
||||||
|
return pony.getAbilities().getActiveStat()
|
||||||
|
.flatMap(Stat::getActiveAbility)
|
||||||
|
.map(ability -> ability.getColor(pony))
|
||||||
|
.filter(i -> i != -1).or(() -> pony.getSpellSlot().get(SpellPredicate.IS_NOT_PLACED, false).map(spell -> spell.getType().getColor()));
|
||||||
|
}).ifPresent(color -> {
|
||||||
|
model.setState(true);
|
||||||
|
model.render(stack, ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayers.getMagicColored(color), false, false), lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HornModel extends Model {
|
||||||
|
|
||||||
|
private final ModelPart part;
|
||||||
|
|
||||||
|
public HornModel(ModelPart tree) {
|
||||||
|
super(RenderLayer::getEntityTranslucent);
|
||||||
|
part = tree.getChild(EntityModelPartNames.HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TexturedModelData getData(Dilation dilation) {
|
||||||
|
ModelData data = new ModelData();
|
||||||
|
ModelPartData root = data.getRoot();
|
||||||
|
|
||||||
|
ModelPartData head = root.addChild(EntityModelPartNames.HEAD, ModelPartBuilder.create()
|
||||||
|
.uv(0, 0)
|
||||||
|
.cuboid(-4, -8, -4, 8, 8, 8, dilation), ModelTransform.NONE);
|
||||||
|
head.addChild("horn", ModelPartBuilder.create()
|
||||||
|
.uv(0, 3)
|
||||||
|
.cuboid(-0.5F, -11, -3.5F, 1, 4, 1, dilation), ModelTransform.rotation(29 * MathHelper.RADIANS_PER_DEGREE, 0, 0));
|
||||||
|
head.addChild("magic", ModelPartBuilder.create()
|
||||||
|
.uv(0, 3)
|
||||||
|
.cuboid(-0.5F, -11, -3.5F, 1, 4, 1, dilation.add(0.5F)), ModelTransform.rotation(29 * MathHelper.RADIANS_PER_DEGREE, 0, 0));
|
||||||
|
|
||||||
|
return TexturedModelData.of(data, 64, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAngles(BipedEntityModel<?> biped) {
|
||||||
|
part.copyTransform(biped.getHead());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(boolean magic) {
|
||||||
|
part.hidden = true;
|
||||||
|
part.getChild("horn").visible = !magic;
|
||||||
|
part.getChild("magic").visible = magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrixStack, VertexConsumer vertexConsumer, int i, int j, float f, float g, float h, float k) {
|
||||||
|
part.render(matrixStack, vertexConsumer, i, j, f, g, h, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Loading…
Reference in a new issue