Added a rainboom ability for pegasi

This commit is contained in:
Sollace 2020-10-14 21:07:36 +02:00
parent 4596b474b0
commit 38f1cc99c8
24 changed files with 667 additions and 106 deletions

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia;
import net.fabricmc.fabric.api.tag.TagRegistry;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
@ -13,6 +14,8 @@ public interface UTags {
Tag<Item> FAIRLY_TOXIC = register("fairly_toxic");
Tag<Item> SEVERELY_TOXIC = register("severely_toxic");
Tag<Block> FRAGILE = TagRegistry.block(new Identifier("unicopia", "fragile"));
static Tag<Item> register(String name) {
return TagRegistry.item(new Identifier("unicopia", name));
}

View file

@ -24,6 +24,9 @@ public interface Abilities {
Ability<?> GROW = register(new EarthPonyGrowAbility(), "grow", AbilitySlot.SECONDARY);
Ability<?> STOMP = register(new EarthPonyStompAbility(), "stomp", AbilitySlot.TERTIARY);
// pegasus
Ability<?> RAINBOOM = register(new PegasusRainboomAbility(), "rainboom", AbilitySlot.PRIMARY);
// pegasus / bat / alicorn / changeling
Ability<?> CARRY = register(new CarryAbility(), "carry", AbilitySlot.PASSIVE);

View file

@ -0,0 +1,83 @@
package com.minelittlepony.unicopia.ability;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.util.math.Vec3d;
/**
* Changeling ability to restore health from mobs
*/
public class PegasusRainboomAbility implements Ability<Hit> {
@Override
public int getWarmupTime(Pony player) {
return 59;
}
@Override
public int getCooldownTime(Pony player) {
return 60;
}
@Override
public boolean canUse(Race race) {
return race.canInteractWithClouds();
}
@Nullable
@Override
public Hit tryActivate(Pony player) {
if (!player.getMaster().isCreative() && player.getMagicalReserves().getMana().getPercentFill() < 0.2F) {
return null;
}
if (player.getPhysics().isFlying() && !player.hasSpell()) {
return Hit.INSTANCE;
}
return null;
}
@Override
public Hit.Serializer<Hit> getSerializer() {
return Hit.SERIALIZER;
}
@Override
public double getCostEstimate(Pony player) {
return player.getMagicalReserves().getMana().getMax() * 0.9F;
}
@Override
public void apply(Pony player, Hit data) {
if (!player.getMaster().isCreative() && player.getMagicalReserves().getMana().getPercentFill() < 0.2F) {
return;
}
if (player.getPhysics().isFlying() && !player.hasSpell()) {
player.getMagicalReserves().getMana().multiply(0.1F);
player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO);
player.setSpell(new JoustingSpell());
}
}
@Override
public void preApply(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(6);
}
@Override
public void postApply(Pony player, AbilitySlot slot) {
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
}
}

View file

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.particle.ParticleSource;
import com.minelittlepony.unicopia.util.VecHelper;
@ -21,6 +22,8 @@ import net.minecraft.world.World;
*/
public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affine, Magical, ParticleSource {
Physics getPhysics();
EffectSync getPrimarySpellSlot();
default void setSpell(@Nullable Spell spell) {

View file

@ -0,0 +1,111 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Thrown;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleHandle;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
public class JoustingSpell extends AbstractRangedAreaSpell implements Thrown {
private final int rad = 5;
private final Shape effect_range = new Sphere(false, rad);
private final ParticleHandle particlEffect = new ParticleHandle();
private int age;
@Override
public String getName() {
return "joust";
}
@Override
public Affinity getAffinity() {
return Affinity.GOOD;
}
@Override
public int getTint() {
return 0xBDBDF9;
}
@Override
public void setDead() {
super.setDead();
particlEffect.destroy();
}
@Override
public boolean update(Caster<?> source) {
LivingEntity owner = source.getMaster();
source.findAllEntitiesInRange(rad).forEach(e -> {
e.damage(MagicalDamageSource.create("rainboom", owner), 6);
});
PosHelper.getAllInRegionMutable(source.getOrigin(), effect_range).forEach(pos -> {
BlockState state = source.getWorld().getBlockState(pos);
if (state.isIn(UTags.FRAGILE) && canBreak(pos, owner)) {
owner.world.breakBlock(pos, true);
}
});
Vec3d motion = source.getEntity().getRotationVec(1).multiply(1.5);
Vec3d velocity = source.getEntity().getVelocity().add(motion);
while (velocity.length() > 3) {
velocity = velocity.multiply(0.6);
}
source.getEntity().setVelocity(velocity);
if (source instanceof Pony) {
((Pony)source).getMagicalReserves().getEnergy().multiply(0.2F);
}
return !source.getEntity().removed && age++ < 90 + 7 * (source.getLevel().get() + 1);
}
private boolean canBreak(BlockPos pos, LivingEntity entity) {
if (entity instanceof PlayerEntity) {
return entity.world.canPlayerModifyAt((PlayerEntity)entity, pos);
}
return entity.world.getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING);
}
@Override
public void render(Caster<?> source) {
particlEffect.ifAbsent(source, spawner -> {
spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO);
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO);
}).ifPresent(p -> p.attach(source));
}
@Override
public void toNBT(CompoundTag compound) {
super.toNBT(compound);
compound.putInt("age", age);
}
@Override
public void fromNBT(CompoundTag compound) {
super.fromNBT(compound);
age = compound.getInt("age");
}
}

View file

@ -39,6 +39,7 @@ public class SpellRegistry {
register(RevealingSpell::new);
register(ScorchSpell::new);
register(DisguiseSpell::new);
register(JoustingSpell::new);
}
@Nullable

View file

@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.client.particle.ChangelingMagicParticle;
import com.minelittlepony.unicopia.client.particle.DiskParticle;
import com.minelittlepony.unicopia.client.particle.MagicParticle;
import com.minelittlepony.unicopia.client.particle.RainboomParticle;
import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle;
import com.minelittlepony.unicopia.client.particle.RaindropsParticle;
import com.minelittlepony.unicopia.client.particle.SphereParticle;
import com.minelittlepony.unicopia.particle.UParticles;
@ -24,6 +25,7 @@ public interface URenderers {
ParticleFactoryRegistry.getInstance().register(UParticles.CHANGELING_MAGIC, createFactory(ChangelingMagicParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.SPHERE, SphereParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.DISK, DiskParticle::new);

View file

@ -0,0 +1,88 @@
package com.minelittlepony.unicopia.client.particle;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public abstract class AbstractBillboardParticle extends Particle {
protected float scale = 1;
public AbstractBillboardParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(world, x, y, z, velocityX, velocityY, velocityZ);
}
@Override
public ParticleTextureSheet getType() {
return ParticleTextureSheet.CUSTOM;
}
@Override
public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) {
Tessellator te = Tessellator.getInstance();
BufferBuilder buffer = te.getBuffer();
MinecraftClient.getInstance().getTextureManager().bindTexture(getTexture());
RenderSystem.disableCull();
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA,
GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA
);
RenderSystem.alphaFunc(516, 0.003921569F);
Vec3d cam = camera.getPos();
float renderX = (float)(MathHelper.lerp(tickDelta, prevPosX, x) - cam.getX());
float renderY = (float)(MathHelper.lerp(tickDelta, prevPosY, y) - cam.getY());
float renderZ = (float)(MathHelper.lerp(tickDelta, prevPosZ, z) - cam.getZ());
renderQuads(te, buffer, renderX, renderY, renderZ, tickDelta);
RenderSystem.enableCull();
RenderSystem.defaultAlphaFunc();
RenderSystem.defaultBlendFunc();
}
protected abstract void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta);
protected void renderQuad(Tessellator te, BufferBuilder buffer, Vector3f[] corners, float alpha, float tickDelta) {
int light = getColorMultiplier(tickDelta);
buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
buffer.vertex(corners[0].getX(), corners[0].getY(), corners[0].getZ()).texture(0, 0).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[1].getX(), corners[1].getY(), corners[1].getZ()).texture(1, 0).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[2].getX(), corners[2].getY(), corners[2].getZ()).texture(1, 1).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[3].getX(), corners[3].getY(), corners[3].getZ()).texture(0, 1).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
te.draw();
}
protected abstract Identifier getTexture();
public float getScale(float tickDelta) {
return scale;
}
@Override
public Particle scale(float scale) {
this.scale = scale;
return super.scale(scale);
}
}

View file

@ -0,0 +1,58 @@
package com.minelittlepony.unicopia.client.particle;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.Quaternion;
public abstract class OrientedBillboardParticle extends AbstractBillboardParticle {
protected boolean fixed;
protected Quaternion rotation = new Quaternion(0, 0, 0, 1);
public OrientedBillboardParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(world, x, y, z, velocityX, velocityY, velocityZ);
fixed = effect.isAngleFixed();
if (!fixed) {
rotation.hamiltonProduct(Vector3f.POSITIVE_X.getDegreesQuaternion(180 - effect.getYaw()));
rotation.hamiltonProduct(Vector3f.POSITIVE_Y.getDegreesQuaternion(effect.getPitch()));
}
}
@Override
public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) {
if (fixed) {
rotation = camera.getRotation();
}
super.buildGeometry(drawer, camera, tickDelta);
}
@Override
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1, -1, 0),
new Vector3f(-1, 1, 0),
new Vector3f( 1, 1, 0),
new Vector3f( 1, -1, 0)
};
float scale = getScale(tickDelta);
for(int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.rotate(rotation);
corner.scale(scale);
corner.add(x, y, z);
}
float alpha = colorAlpha * (1 - ((float)age / maxAge));
renderQuad(te, buffer, corners, alpha, tickDelta);
}
}

View file

@ -1,111 +1,32 @@
package com.minelittlepony.unicopia.client.particle;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.particle.DefaultParticleType;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3d;
public class RainboomParticle extends Particle {
public class RainboomParticle extends OrientedBillboardParticle {
private static final Identifier TEXTURE = new Identifier("unicopia", "textures/particles/rainboom_ring.png");
protected float prevBaseSize = 0;
protected float baseSize = 0;
protected float scale = 1;
protected Quaternion rotation;
public RainboomParticle(DefaultParticleType effect, ClientWorld world, double x, double y, double z, double angleX, double angleY, double angleZ) {
super(world, x, y, z);
rotation = Vector3f.POSITIVE_X.getRadialQuaternion((float)angleX);
rotation.hamiltonProduct(Vector3f.POSITIVE_Y.getRadialQuaternion((float)angleY));
rotation.hamiltonProduct(Vector3f.POSITIVE_Z.getRadialQuaternion((float)angleZ));
public RainboomParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
setMaxAge(40);
}
@Override
public ParticleTextureSheet getType() {
return ParticleTextureSheet.CUSTOM;
public float getScale(float tickDelta) {
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
}
@Override
public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) {
Vec3d cam = camera.getPos();
float renderX = (float)(MathHelper.lerp(tickDelta, prevPosX, x) - cam.getX());
float renderY = (float)(MathHelper.lerp(tickDelta, prevPosY, y) - cam.getY());
float renderZ = (float)(MathHelper.lerp(tickDelta, prevPosZ, z) - cam.getZ());
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1.0F, -1.0F, 0.0F),
new Vector3f(-1.0F, 1.0F, 0.0F),
new Vector3f(1.0F, 1.0F, 0.0F),
new Vector3f(1.0F, -1.0F, 0.0F)
};
float scale = getSize(tickDelta);
for(int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.rotate(rotation);
corner.scale(scale);
corner.add(renderX, renderY, renderZ);
}
float alpha = colorAlpha * (1 - ((float)age / maxAge));
int light = getColorMultiplier(tickDelta);
Tessellator te = Tessellator.getInstance();
BufferBuilder buffer = te.getBuffer();
MinecraftClient.getInstance().getTextureManager().bindTexture(TEXTURE);
RenderSystem.disableCull();
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(
GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA,
GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA
);
RenderSystem.alphaFunc(516, 0.003921569F);
buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
buffer.vertex(corners[0].getX(), corners[0].getY(), corners[0].getZ()).texture(0, 0).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[1].getX(), corners[1].getY(), corners[1].getZ()).texture(1, 0).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[2].getX(), corners[2].getY(), corners[2].getZ()).texture(0, 0).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
buffer.vertex(corners[3].getX(), corners[3].getY(), corners[3].getZ()).texture(0, 1).color(colorRed, colorGreen, colorBlue, alpha).light(light).next();
te.draw();
RenderSystem.enableCull();
RenderSystem.defaultAlphaFunc();
RenderSystem.defaultBlendFunc();
}
public float getSize(float tickDelta) {
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * scale;
}
@Override
public Particle scale(float scale) {
this.scale = scale;
return super.scale(scale);
protected Identifier getTexture() {
return TEXTURE;
}
@Override
@ -115,9 +36,9 @@ public class RainboomParticle extends Particle {
prevBaseSize = baseSize;
baseSize++;
if (this.age == 1) {
this.world.playSound(x, y, z, SoundEvents.ENTITY_LIGHTNING_BOLT_THUNDER, SoundCategory.AMBIENT, 5, 0.3F, true);
this.world.playSound(x, y, z, SoundEvents.ENTITY_LIGHTNING_BOLT_THUNDER, SoundCategory.AMBIENT, 10, 1.3F, true);
if (age == 1) {
world.playSound(x, y, z, SoundEvents.ENTITY_LIGHTNING_BOLT_THUNDER, SoundCategory.AMBIENT, 5, 0.3F, true);
world.playSound(x, y, z, SoundEvents.ENTITY_LIGHTNING_BOLT_THUNDER, SoundCategory.AMBIENT, 10, 1.3F, true);
}
}
}

View file

@ -0,0 +1,147 @@
package com.minelittlepony.unicopia.client.particle;
import java.util.ArrayList;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.particle.DefaultParticleType;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
public class RainbowTrailParticle extends AbstractBillboardParticle implements Attachment {
private static final Identifier TEXTURE = new Identifier("unicopia", "textures/particles/rainboom_trail.png");
private final List<Segment> segments = new ArrayList<>();
private final Link link = new Link();
public RainbowTrailParticle(DefaultParticleType effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(world, x, y, z, velocityX, velocityY, velocityZ);
segments.add(new Segment(new Vec3d(x, y, z)));
}
@Override
protected Identifier getTexture() {
return TEXTURE;
}
@Override
public boolean isStillAlive() {
return age < (maxAge - 1);
}
@Override
public void attach(Caster<?> caster) {
link.attach(caster);
}
@Override
public void detach() {
link.detach();
}
@Override
public void setAttribute(int key, Object value) {
}
@Override
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
for (int i = 0; i < segments.size() - 1; i++) {
Vector3f[] corners = segments.get(i).getPlane(segments.get(i + 1));
float scale = getScale(tickDelta);
for (int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.scale(scale);
corner.add(x, y, z);
}
renderQuad(te, buffer, corners, segments.get(i).getAlpha(), tickDelta);
}
}
private void follow(Caster<?> caster) {
Vec3d next = caster.getOriginVector();
if (segments.isEmpty()) {
segments.add(new Segment(next));
} else {
Vec3d last = segments.get(segments.size() - 1).position;
if (next.distanceTo(last) > 0.2) {
segments.add(new Segment(next));
}
}
}
@Override
public void tick() {
super.tick();
age = 0;
if (link.linked()) {
link.ifAbsent(() -> {}).ifPresent(this::follow);
} else {
follow(Pony.of(MinecraftClient.getInstance().player));
}
if (segments.size() > 1) {
segments.removeIf(Segment::tick);
}
if (segments.isEmpty()) {
markDead();
}
}
private final class Segment {
Vec3d position;
Vector3f offset;
int age;
int maxAge;
Segment(Vec3d position) {
this.position = position;
this.offset = new Vector3f((float)(position.getX() - x), (float)(position.getY() - y), (float)(position.getZ() - z));
this.maxAge = 90;
}
float getAlpha() {
return colorAlpha * (1 - ((float)age / maxAge));
}
boolean tick() {
return segments.indexOf(this) < segments.size() - 1 && age++ >= maxAge;
}
Vector3f[] getPlane(Segment to) {
float fromX = offset.getX();
float toX = to.offset.getX();
float fromZ = offset.getZ();
float toZ = to.offset.getZ();
float fromTopY = offset.getY() + 1;
float fromBottomY = offset.getY();
float toTopY = to.offset.getY() + 1;
float toBottomY = to.offset.getY();
return new Vector3f[]{
new Vector3f(fromX, fromBottomY, fromZ), // bottom left
new Vector3f(fromX, fromTopY, fromZ), // top left
new Vector3f(toX, toTopY, toZ), // top right
new Vector3f(toX, toBottomY, toZ) // bottom right
};
}
}
}

View file

@ -9,7 +9,6 @@ import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.network.EffectSync;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;

View file

@ -16,7 +16,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class EntityPhysics<T extends Equine<?> & Owned<? extends Entity>> implements Physics, Copieable<EntityPhysics<T>> {
public class EntityPhysics<T extends Owned<? extends Entity>> implements Physics, Copieable<EntityPhysics<T>> {
private float gravity = 1;
@ -31,6 +31,11 @@ public class EntityPhysics<T extends Equine<?> & Owned<? extends Entity>> implem
return false;
}
@Override
public Vec3d getMotionAngle() {
return new Vec3d(pony.getMaster().getPitch(1), pony.getMaster().getYaw(1), 0);
}
@Override
public double calcGravity(double worldConstant) {
return worldConstant * getGravityModifier();
@ -94,17 +99,11 @@ public class EntityPhysics<T extends Equine<?> & Owned<? extends Entity>> implem
@Override
public void toNBT(CompoundTag compound) {
if (gravity != 0) {
compound.putFloat("gravity", gravity);
}
}
@Override
public void fromNBT(CompoundTag compound) {
if (compound.contains("gravity")) {
gravity = compound.getFloat("gravity");
} else {
gravity = 0;
}
}
}

View file

@ -3,11 +3,14 @@ package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public interface Physics extends NbtSerialisable {
double calcGravity(double worldConstant);
Vec3d getMotionAngle();
float getGravityModifier();
void setBaseGravityModifier(float constant);

View file

@ -344,5 +344,4 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
pony.getMaster().calculateDimensions();
}
}

View file

@ -310,7 +310,6 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
prevSneaking = entity.isSneaking();
prevLanded = entity.isOnGround();
if (gravity.isGravityNegative() && entity.getY() > entity.world.getHeight() + 64) {
entity.damage(DamageSource.OUT_OF_WORLD, 4.0F);
}

View file

@ -14,7 +14,7 @@ import net.minecraft.util.registry.Registry;
public class MagicParticleEffect implements ParticleEffect {
public static final MagicParticleEffect UNICORN = new MagicParticleEffect(false, 0, 0, 0);
public static final ParticleEffect.Factory<MagicParticleEffect> UNICORN_FACTORY = new ParticleEffect.Factory<MagicParticleEffect>() {
public static final ParticleEffect.Factory<MagicParticleEffect> FACTORY = new ParticleEffect.Factory<MagicParticleEffect>() {
@Override
public MagicParticleEffect read(ParticleType<MagicParticleEffect> particleType, StringReader reader) throws CommandSyntaxException {
reader.expect(' ');

View file

@ -0,0 +1,83 @@
package com.minelittlepony.unicopia.particle;
import java.util.Locale;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleType;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry;
public class OrientedBillboardParticleEffect implements ParticleEffect {
public static final ParticleEffect.Factory<OrientedBillboardParticleEffect> FACTORY = new ParticleEffect.Factory<OrientedBillboardParticleEffect>() {
@Override
public OrientedBillboardParticleEffect read(ParticleType<OrientedBillboardParticleEffect> type, StringReader reader) throws CommandSyntaxException {
reader.expect(' ');
boolean fixed = reader.readBoolean();
reader.expect(' ');
float yaw = (float)reader.readDouble();
reader.expect(' ');
float pitch = (float)reader.readDouble();
return new OrientedBillboardParticleEffect(type, fixed, yaw, pitch);
}
@Override
public OrientedBillboardParticleEffect read(ParticleType<OrientedBillboardParticleEffect> particleType, PacketByteBuf buf) {
return new OrientedBillboardParticleEffect(particleType, buf.readBoolean(), buf.readFloat(), buf.readFloat());
}
};
private final boolean fixed;
private final float yaw;
private final float pitch;
private final ParticleType<OrientedBillboardParticleEffect> type;
public OrientedBillboardParticleEffect(ParticleType<OrientedBillboardParticleEffect> type, Vec3d orientation) {
this(type, (float)orientation.getX(), (float)orientation.getY());
}
public OrientedBillboardParticleEffect(ParticleType<OrientedBillboardParticleEffect> type, float yaw, float pitch) {
this(type, true, yaw, pitch);
}
private OrientedBillboardParticleEffect(ParticleType<OrientedBillboardParticleEffect> type, boolean fixed, float yaw, float pitch) {
this.fixed = fixed;
this.yaw = yaw;
this.pitch = pitch;
this.type = type;
}
public boolean isAngleFixed() {
return fixed;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
}
@Override
public ParticleType<?> getType() {
return type;
}
@Override
public void write(PacketByteBuf buf) {
buf.writeBoolean(fixed);
buf.writeFloat(yaw);
buf.writeFloat(pitch);
}
@Override
public String asString() {
return String.format(Locale.ROOT, "%s %b %.2f %.2f", Registry.PARTICLE_TYPE.getId(getType()), fixed, yaw, pitch);
}
}

View file

@ -68,6 +68,11 @@ public class ParticleHandle {
this.effect = caster.getSpell(false).getName();
}
public void detach() {
linked = false;
caster = Optional.empty();
}
public boolean linked() {
return linked;
}

View file

@ -8,10 +8,11 @@ import net.minecraft.util.registry.Registry;
public interface UParticles {
ParticleType<MagicParticleEffect> UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.UNICORN_FACTORY));
ParticleType<MagicParticleEffect> UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.FACTORY));
DefaultParticleType CHANGELING_MAGIC = register("changeling_magic", FabricParticleTypes.simple());
DefaultParticleType RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.simple());
ParticleType<OrientedBillboardParticleEffect> RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
DefaultParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.simple());
DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple());

View file

@ -7,6 +7,8 @@ import com.minelittlepony.unicopia.ability.magic.Magical;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.Thrown;
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
@ -49,6 +51,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this);
private BlockPos lastBlockPos;
public MagicProjectileEntity(EntityType<MagicProjectileEntity> type, World world) {
@ -97,6 +101,11 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
return LEVELS;
}
@Override
public Physics getPhysics() {
return physics;
}
@Override
public Affinity getAffinity() {
return hasSpell() ? Affinity.NEUTRAL : getSpell(true).getAffinity();
@ -206,7 +215,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override
public void readCustomDataFromTag(CompoundTag compound) {
super.readCustomDataFromTag(compound);
physics.fromNBT(compound);
if (compound.contains("effect")) {
setSpell(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
}
@ -215,6 +224,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override
public void writeCustomDataToTag(CompoundTag compound) {
super.writeCustomDataToTag(compound);
physics.toNBT(compound);
if (hasSpell()) {
compound.put("effect", SpellRegistry.toNBT(getSpell(true)));

View file

@ -0,0 +1,2 @@
{
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,41 @@
{
"replace": false,
"values": [
"minecraft:glass",
"minecraft:glass_pane",
"minecraft:white_stained_glass",
"minecraft:orange_stained_glass",
"minecraft:magenta_stained_glass",
"minecraft:light_blue_stained_glass",
"minecraft:yellow_stained_glass",
"minecraft:lime_stained_glass",
"minecraft:pink_stained_glass",
"minecraft:gray_stained_glass",
"minecraft:light_gray_stained_glass",
"minecraft:cyan_stained_glass",
"minecraft:purple_stained_glass",
"minecraft:blue_stained_glass",
"minecraft:brown_stained_glass",
"minecraft:green_stained_glass",
"minecraft:red_stained_glass",
"minecraft:black_stained_glass",
"minecraft:white_stained_glass_pane",
"minecraft:orange_stained_glass_pane",
"minecraft:magenta_stained_glass_pane",
"minecraft:light_blue_stained_glass_pane",
"minecraft:yellow_stained_glass_pane",
"minecraft:lime_stained_glass_pane",
"minecraft:pink_stained_glass_pane",
"minecraft:gray_stained_glass_pane",
"minecraft:light_gray_stained_glass_pane",
"minecraft:cyan_stained_glass_pane",
"minecraft:purple_stained_glass_pane",
"minecraft:blue_stained_glass_pane",
"minecraft:brown_stained_glass_pane",
"minecraft:green_stained_glass_pane",
"minecraft:red_stained_glass_pane",
"minecraft:black_stained_glass_pane",
"minecraft:vine",
"minecraft:lily_pad"
]
}