mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Portal refinements and add the displacement spell
This commit is contained in:
parent
4fde8400c5
commit
af7e19ae69
18 changed files with 329 additions and 93 deletions
|
@ -117,8 +117,8 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
|||
player.playSound(USounds.SPELL_CAST_FAIL, 1, 0.5F);
|
||||
} else {
|
||||
player.setAnimation(Animation.ARMS_UP);
|
||||
if (s instanceof HomingSpell) {
|
||||
RayTraceHelper.doTrace(player.getMaster(), 600, 1, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_ENTITY)).getEntity().ifPresent(((HomingSpell)s)::setTarget);
|
||||
if (s instanceof HomingSpell homer) {
|
||||
RayTraceHelper.doTrace(player.getMaster(), homer.getRange(player), 1, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_ENTITY)).getEntity().ifPresent(homer::setTarget);
|
||||
}
|
||||
player.playSound(USounds.SPELL_CAST_SUCCESS, 0.05F, 2.2F);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
|
|||
@Override
|
||||
public void apply(Pony player, Pos data) {
|
||||
player.setAnimation(Animation.WOLOLO);
|
||||
Caster.stream(VecHelper.findInRange(player.getEntity(), player.getReferenceWorld(), data.vec(), 2, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
|
||||
Caster.stream(VecHelper.findInRange(player.getEntity(), player.getReferenceWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
|
||||
target.getSpellSlot().clear();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ package com.minelittlepony.unicopia.ability.data;
|
|||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.*;
|
||||
|
||||
public class Pos extends Hit {
|
||||
|
||||
|
@ -44,7 +43,7 @@ public class Pos extends Hit {
|
|||
}
|
||||
|
||||
public Vec3d vec() {
|
||||
return new Vec3d(x, y, z);
|
||||
return Vec3d.ofCenter(new Vec3i(x, y, z));
|
||||
}
|
||||
|
||||
public double distanceTo(Caster<?> caster) {
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
/**
|
||||
* A spell that's capable of homing in on a pre-defined target.
|
||||
*/
|
||||
public interface HomingSpell extends Spell {
|
||||
int DEFAULT_RANGE = 600;
|
||||
|
||||
boolean setTarget(Entity target);
|
||||
|
||||
default int getRange(Caster<?> caster) {
|
||||
return DEFAULT_RANGE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
*/
|
||||
private Spell spell;
|
||||
|
||||
public float pitch;
|
||||
public float yaw;
|
||||
|
||||
public PlaceableSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
@ -84,7 +87,11 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
CastSpellEntity entity = UEntities.CAST_SPELL.create(source.getReferenceWorld());
|
||||
Vec3d pos = castEntity.getPosition().orElse(source.getOriginVector());
|
||||
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, 0, 0);
|
||||
entity.getSpellSlot().put(spell.toPlaceable());
|
||||
PlaceableSpell copy = spell.toPlaceable();
|
||||
if (spell instanceof PlacementDelegate delegate) {
|
||||
delegate.onPlaced(source, copy, entity);
|
||||
}
|
||||
entity.getSpellSlot().put(copy);
|
||||
entity.setMaster(source);
|
||||
entity.world.spawnEntity(entity);
|
||||
Ether.get(entity.world).put(getType(), entity);
|
||||
|
@ -113,9 +120,11 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
}
|
||||
}
|
||||
|
||||
particlEffect.update(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
if (spell instanceof PlacementDelegate delegate) {
|
||||
delegate.updatePlacement(source, this);
|
||||
}
|
||||
|
||||
getParticleEffectAttachment(source).ifPresent(p -> {
|
||||
p.setAttribute(Attachment.ATTR_COLOR, spell.getType().getColor());
|
||||
});
|
||||
|
||||
|
@ -145,6 +154,13 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
return getWorld(source).map(castEntity::get);
|
||||
}
|
||||
|
||||
public Optional<Attachment> getParticleEffectAttachment(Caster<?> source) {
|
||||
return particlEffect.update(getUuid(), source, spawner -> {
|
||||
source.getOriginVector().add(0, 5, 0);
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, pitch + 90, yaw), Vec3d.ZERO, Vec3d.ZERO);
|
||||
});
|
||||
}
|
||||
|
||||
protected Optional<World> getWorld(Caster<?> source) {
|
||||
return Optional.ofNullable(dimension)
|
||||
.map(dim -> source.getReferenceWorld().getServer().getWorld(dim));
|
||||
|
@ -153,6 +169,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
super.toNBT(compound);
|
||||
compound.putFloat("pitch", pitch);
|
||||
compound.putFloat("yaw", yaw);
|
||||
if (dimension != null) {
|
||||
compound.putString("dimension", dimension.getValue().toString());
|
||||
}
|
||||
|
@ -163,6 +181,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
super.fromNBT(compound);
|
||||
pitch = compound.getFloat("pitch");
|
||||
yaw = compound.getFloat("yaw");
|
||||
if (compound.contains("dimension", NbtElement.STRING_TYPE)) {
|
||||
Identifier id = Identifier.tryParse(compound.getString("dimension"));
|
||||
if (id != null) {
|
||||
|
@ -182,10 +202,18 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
@Override
|
||||
protected void saveDelegates(NbtCompound compound) {
|
||||
compound.put("spell", Spell.SERIALIZER.write(spell));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceableSpell toPlaceable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public interface PlacementDelegate {
|
||||
|
||||
void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity);
|
||||
|
||||
void updatePlacement(Caster<?> source, PlaceableSpell parent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.*;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||
import com.minelittlepony.unicopia.entity.CastSpellEntity;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class DisplacementSpell extends AbstractSpell implements HomingSpell, PlaceableSpell.PlacementDelegate {
|
||||
|
||||
private final EntityReference<Entity> target = new EntityReference<>();
|
||||
|
||||
private int ticks = 10;
|
||||
|
||||
protected DisplacementSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Caster<?> caster) {
|
||||
return toPlaceable().apply(caster);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tick(Caster<?> source, Situation situation) {
|
||||
source.getMaster().setGlowing(true);
|
||||
|
||||
ticks--;
|
||||
|
||||
if (source.isClient()) {
|
||||
return !isDead() || ticks >= -10;
|
||||
}
|
||||
|
||||
if (ticks == 0) {
|
||||
target.ifPresent(source.getReferenceWorld(), target -> {
|
||||
|
||||
Vec3d destinationPos = target.getPos();
|
||||
Vec3d destinationVel = target.getVelocity();
|
||||
|
||||
Vec3d sourcePos = source.getMaster().getPos();
|
||||
Vec3d sourceVel = source.getMaster().getVelocity();
|
||||
|
||||
teleport(target, sourcePos, sourceVel);
|
||||
teleport(source.getMaster(), destinationPos, destinationVel);
|
||||
source.subtractEnergyCost(destinationPos.distanceTo(sourcePos) / 20F);
|
||||
});
|
||||
}
|
||||
|
||||
return ticks >= -10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlacement(Caster<?> caster, PlaceableSpell parent) {
|
||||
parent.getParticleEffectAttachment(caster).ifPresent(attachment -> {
|
||||
float r = 3 - (1 - ((ticks + 10) / 20F)) * 3;
|
||||
attachment.setAttribute(Attachment.ATTR_RADIUS, r);
|
||||
});
|
||||
}
|
||||
|
||||
private void teleport(Entity entity, Vec3d pos, Vec3d vel) {
|
||||
entity.teleport(pos.x, pos.y, pos.z);
|
||||
entity.setVelocity(vel);
|
||||
entity.setGlowing(false);
|
||||
entity.playSound(SoundEvents.ENTITY_HUSK_CONVERTED_TO_ZOMBIE, 1, 1);
|
||||
|
||||
float damage = getTraits().get(Trait.BLOOD);
|
||||
if (damage > 0) {
|
||||
entity.damage(MagicalDamageSource.EXHAUSTION, damage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTarget(Entity target) {
|
||||
this.target.set(target);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRange(Caster<?> caster) {
|
||||
return 200 + Math.min(2000, 50 * (1 + caster.getLevel().get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
caster.getMaster().setGlowing(false);
|
||||
target.ifPresent(caster.getReferenceWorld(), e -> e.setGlowing(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
super.toNBT(compound);
|
||||
compound.putInt("ticks", ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
super.fromNBT(compound);
|
||||
ticks = compound.getInt("ticks");
|
||||
}
|
||||
}
|
|
@ -1,32 +1,46 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.*;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||
import com.minelittlepony.unicopia.block.data.Ether;
|
||||
import com.minelittlepony.unicopia.entity.CastSpellEntity;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.particle.*;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.WorldEvents;
|
||||
|
||||
public class PortalSpell extends AbstractSpell {
|
||||
public static final int MAX_COOLDOWN = 20;
|
||||
private final EntityReference<CastSpellEntity> teleportationTarget = new EntityReference<>();
|
||||
public class PortalSpell extends AbstractSpell implements PlaceableSpell.PlacementDelegate {
|
||||
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||
.with(Trait.LIFE, 10)
|
||||
.with(Trait.KNOWLEDGE, 1)
|
||||
.with(Trait.ORDER, 25)
|
||||
.build();
|
||||
|
||||
private final EntityReference<Entity> teleportationTarget = new EntityReference<>();
|
||||
|
||||
private boolean publishedPosition;
|
||||
|
||||
private final ParticleHandle particlEffect = new ParticleHandle();
|
||||
private final ParticleHandle particleEffect = new ParticleHandle();
|
||||
|
||||
private int cooldown = MAX_COOLDOWN;
|
||||
private float pitch;
|
||||
private float yaw;
|
||||
|
||||
protected PortalSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
|
@ -34,36 +48,17 @@ public class PortalSpell extends AbstractSpell {
|
|||
|
||||
@Override
|
||||
public boolean apply(Caster<?> caster) {
|
||||
pitch = caster.getEntity().getPitch(1);
|
||||
yaw = caster.getEntity().getYaw(1);
|
||||
return toPlaceable().apply(caster);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tick(Caster<?> source, Situation situation) {
|
||||
|
||||
if (situation == Situation.GROUND) {
|
||||
if (!source.isClient()) {
|
||||
teleportationTarget.getId().ifPresent(id -> {
|
||||
Ether ether = Ether.get(source.getReferenceWorld());
|
||||
if (ether.getEntry(getType(), id).isEmpty()) {
|
||||
Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + id);
|
||||
teleportationTarget.set(null);
|
||||
setDirty();
|
||||
source.getReferenceWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
teleportationTarget.getPosition().ifPresentOrElse(
|
||||
targetPos -> tickWithTargetLink(source, targetPos),
|
||||
() -> findLink(source)
|
||||
);
|
||||
if (source.isClient()) {
|
||||
|
||||
if (!publishedPosition) {
|
||||
publishedPosition = true;
|
||||
Ether.get(source.getReferenceWorld()).put(getType(), source);
|
||||
}
|
||||
|
||||
if (source.isClient() && cooldown <= 0) {
|
||||
Vec3d origin = source.getOriginVector();
|
||||
|
||||
ParticleEffect effect = teleportationTarget.getPosition()
|
||||
|
@ -71,51 +66,78 @@ public class PortalSpell extends AbstractSpell {
|
|||
getType();
|
||||
return new FollowingParticleEffect(UParticles.HEALTH_DRAIN, target, 0.2F).withChild(ParticleTypes.ELECTRIC_SPARK);
|
||||
})
|
||||
.orElseGet(() -> {
|
||||
new MagicParticleEffect(getType().getColor());
|
||||
return ParticleTypes.ELECTRIC_SPARK;
|
||||
});
|
||||
.orElse(ParticleTypes.ELECTRIC_SPARK);
|
||||
|
||||
source.spawnParticles(origin, new Sphere(true, 2, 1, 0, 1), 3, pos -> {
|
||||
source.spawnParticles(origin, new Sphere(true, 2, 1, 1, 1), 1, pos -> {
|
||||
source.addParticle(effect, pos, Vec3d.ZERO);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
teleportationTarget.getPosition().ifPresentOrElse(position -> {
|
||||
particleEffect.update(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new SphereParticleEffect(UParticles.DISK, getType().getColor(), 0.8F, 2, new Vec3d(pitch, yaw, 0)), source.getOriginVector(), Vec3d.ZERO);
|
||||
});
|
||||
}, () -> {
|
||||
particleEffect.destroy();
|
||||
});
|
||||
} else {
|
||||
teleportationTarget.getId().ifPresent(id -> {
|
||||
if (Ether.get(source.getReferenceWorld()).getEntry(getType(), id).isEmpty()) {
|
||||
Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + id);
|
||||
teleportationTarget.set(null);
|
||||
setDirty();
|
||||
source.getReferenceWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState()));
|
||||
}
|
||||
|
||||
private void tickWithTargetLink(Caster<?> source, Vec3d targetPos) {
|
||||
particlEffect.update(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new SphereParticleEffect(UParticles.DISK, getType().getColor(), 0.8F, 2), source.getOriginVector(), Vec3d.ZERO);
|
||||
});
|
||||
|
||||
if (cooldown > 0) {
|
||||
cooldown--;
|
||||
setDirty();
|
||||
return;
|
||||
getTarget(source).ifPresentOrElse(
|
||||
entry -> tickWithTargetLink(source, entry),
|
||||
() -> findLink(source)
|
||||
);
|
||||
}
|
||||
|
||||
if (!publishedPosition) {
|
||||
publishedPosition = true;
|
||||
Ether.Entry entry = Ether.get(source.getReferenceWorld()).put(getType(), source);
|
||||
entry.pitch = pitch;
|
||||
entry.yaw = yaw;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
private void tickWithTargetLink(Caster<?> source, Ether.Entry destination) {
|
||||
|
||||
destination.entity.getPosition().ifPresent(targetPos -> {
|
||||
Vec3d center = source.getOriginVector();
|
||||
source.findAllEntitiesInRange(1).filter(e -> true).forEach(entity -> {
|
||||
if (!entity.hasPortalCooldown() && entity.timeUntilRegen <= 0) {
|
||||
Vec3d destination = entity.getPos().subtract(center).add(targetPos);
|
||||
entity.resetPortalCooldown();
|
||||
entity.timeUntilRegen = 100;
|
||||
Vec3d offset = entity.getPos().subtract(center);
|
||||
Vec3d dest = targetPos;
|
||||
float yawDifference = pitch < 15 ? (180 - yaw + destination.yaw) : 0;
|
||||
|
||||
entity.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1, 1);
|
||||
entity.teleport(destination.x, destination.y, destination.z);
|
||||
entity.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1, 1);
|
||||
dest = dest.add(offset.rotateY(yawDifference * MathHelper.RADIANS_PER_DEGREE)).add(0, 0.05, 0);
|
||||
|
||||
entity.resetPortalCooldown();
|
||||
entity.timeUntilRegen = 20;
|
||||
|
||||
entity.setYaw(entity.getYaw() + yawDifference);
|
||||
entity.setVelocity(entity.getVelocity().rotateY(yawDifference * MathHelper.RADIANS_PER_DEGREE));
|
||||
|
||||
entity.world.playSoundFromEntity(null, entity, USounds.ENTITY_PLAYER_UNICORN_TELEPORT, entity.getSoundCategory(), 1, 1);
|
||||
entity.teleport(dest.x, dest.y, dest.z);
|
||||
entity.world.playSoundFromEntity(null, entity, USounds.ENTITY_PLAYER_UNICORN_TELEPORT, entity.getSoundCategory(), 1, 1);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), entity, 7);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void findLink(Caster<?> source) {
|
||||
|
||||
if (source.isClient()) {
|
||||
return;
|
||||
}
|
||||
|
@ -123,20 +145,50 @@ public class PortalSpell extends AbstractSpell {
|
|||
Ether ether = Ether.get(source.getReferenceWorld());
|
||||
ether.getEntries(getType())
|
||||
.stream()
|
||||
.filter(entry -> entry.isAvailable() && !entry.entity.referenceEquals(source.getEntity()))
|
||||
.filter(entry -> entry.isAvailable() && !entry.entity.referenceEquals(source.getEntity()) && entry.entity.getId().isPresent())
|
||||
.findAny()
|
||||
.ifPresent(entry -> {
|
||||
entry.setTaken(true);
|
||||
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)entry.entity);
|
||||
teleportationTarget.copyFrom(entry.entity);
|
||||
setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<Ether.Entry> getTarget(Caster<?> source) {
|
||||
return teleportationTarget.getId().flatMap(id -> Ether.get(source.getReferenceWorld()).getEntry(getType(), id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity) {
|
||||
LivingEntity caster = source.getMaster();
|
||||
Vec3d targetPos = caster.getRotationVector().multiply(3).add(caster.getEyePos());
|
||||
|
||||
parent.pitch = -90 - pitch;
|
||||
parent.yaw = -yaw;
|
||||
|
||||
for (Spell delegate : parent.getDelegates()) {
|
||||
if (delegate instanceof PortalSpell copy) {
|
||||
copy.pitch = pitch;
|
||||
copy.yaw = yaw;
|
||||
}
|
||||
}
|
||||
|
||||
entity.setPos(targetPos.x, caster.getY() + 1.5, targetPos.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlacement(Caster<?> source, PlaceableSpell parent) {
|
||||
parent.getParticleEffectAttachment(source).ifPresent(attachment -> {
|
||||
attachment.setAttribute(Attachment.ATTR_RADIUS, 2);
|
||||
attachment.setAttribute(Attachment.ATTR_OPACITY, 0.92F);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
Ether ether = Ether.get(caster.getReferenceWorld());
|
||||
ether.remove(getType(), caster.getEntity().getUuid());
|
||||
teleportationTarget.getId().flatMap(id -> ether.getEntry(getType(), id)).ifPresent(e -> e.setTaken(false));
|
||||
getTarget(caster).ifPresent(e -> e.setTaken(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,7 +196,8 @@ public class PortalSpell extends AbstractSpell {
|
|||
super.toNBT(compound);
|
||||
compound.putBoolean("publishedPosition", publishedPosition);
|
||||
compound.put("teleportationTarget", teleportationTarget.toNBT());
|
||||
compound.putInt("cooldown", cooldown);
|
||||
compound.putFloat("pitch", pitch);
|
||||
compound.putFloat("yaw", yaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,12 +205,13 @@ public class PortalSpell extends AbstractSpell {
|
|||
super.fromNBT(compound);
|
||||
publishedPosition = compound.getBoolean("publishedPosition");
|
||||
teleportationTarget.fromNBT(compound.getCompound("teleportationTarget"));
|
||||
cooldown = compound.getInt("cooldown");
|
||||
pitch = compound.getFloat("pitch");
|
||||
yaw = compound.getFloat("yaw");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
particlEffect.destroy();
|
||||
particleEffect.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
|||
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", Affinity.GOOD, 0x22FF00, true, CatapultSpell.DEFAULT_TRAITS, CatapultSpell::new);
|
||||
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", Affinity.GOOD, 0xFF8811, true, FireBoltSpell.DEFAULT_TRAITS, FireBoltSpell::new);
|
||||
public static final SpellType<LightSpell> LIGHT = register("light", Affinity.GOOD, 0xEEFFAA, true, LightSpell.DEFAULT_TRAITS, LightSpell::new);
|
||||
public static final SpellType<PortalSpell> PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, LightSpell.DEFAULT_TRAITS, PortalSpell::new);
|
||||
public static final SpellType<DisplacementSpell> DISPLACEMENT = register("displacement", Affinity.NEUTRAL, 0x9900FF, true, PortalSpell.DEFAULT_TRAITS, DisplacementSpell::new);
|
||||
public static final SpellType<PortalSpell> PORTAL = register("portal", Affinity.GOOD, 0x99FFFF, true, PortalSpell.DEFAULT_TRAITS, PortalSpell::new);
|
||||
|
||||
public static void bootstrap() {}
|
||||
|
||||
|
|
|
@ -61,11 +61,12 @@ public class Ether extends PersistentState {
|
|||
}
|
||||
}
|
||||
|
||||
public void put(SpellType<?> spellType, Caster<?> caster) {
|
||||
public Entry put(SpellType<?> spellType, Caster<?> caster) {
|
||||
synchronized (locker) {
|
||||
getEntries(spellType.getId()).add(new Entry(caster));
|
||||
}
|
||||
markDirty();
|
||||
return getEntry(spellType, caster).get();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(SpellType<?> spellType, UUID id) {
|
||||
|
@ -120,6 +121,9 @@ public class Ether extends PersistentState {
|
|||
private boolean removed;
|
||||
private boolean taken;
|
||||
|
||||
public float pitch;
|
||||
public float yaw;
|
||||
|
||||
public Entry() {
|
||||
entity = new EntityReference<>();
|
||||
}
|
||||
|
@ -156,6 +160,8 @@ public class Ether extends PersistentState {
|
|||
entity.toNBT(compound);
|
||||
compound.putBoolean("removed", removed);
|
||||
compound.putBoolean("taken", taken);
|
||||
compound.putFloat("pitch", pitch);
|
||||
compound.putFloat("yaw", yaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -163,6 +169,8 @@ public class Ether extends PersistentState {
|
|||
entity.fromNBT(compound);
|
||||
removed = compound.getBoolean("removed");
|
||||
taken = compound.getBoolean("taken");
|
||||
pitch = compound.getFloat("pitch");
|
||||
yaw = compound.getFloat("yaw");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,15 +5,19 @@ import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
|||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.math.Quaternion;
|
||||
import net.minecraft.util.math.*;
|
||||
|
||||
public class DiskParticle extends SphereParticle {
|
||||
|
||||
private final Quaternion rotation;
|
||||
private final Quaternion rotation = new Quaternion(0, 0, 0, 1);
|
||||
|
||||
public DiskParticle(SphereParticleEffect effect, ClientWorld w, double x, double y, double z, double rX, double rY, double rZ) {
|
||||
super(effect, w, x, y, z, 0, 0, 0);
|
||||
rotation = new Quaternion((float)effect.getOffset().x, (float)effect.getOffset().y, (float)effect.getOffset().z, true);
|
||||
|
||||
rotation.hamiltonProduct(Vec3f.POSITIVE_Y.getDegreesQuaternion((float)effect.getOffset().y));
|
||||
rotation.hamiltonProduct(Vec3f.POSITIVE_X.getDegreesQuaternion(90 - (float)effect.getOffset().x));
|
||||
|
||||
effect.setOffset(Vec3d.ZERO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,8 +20,8 @@ public abstract class OrientedBillboardParticle extends AbstractBillboardParticl
|
|||
|
||||
fixed = effect.isAngleFixed();
|
||||
if (fixed) {
|
||||
rotation.hamiltonProduct(Vec3f.POSITIVE_X.getDegreesQuaternion(180 - effect.getYaw()));
|
||||
rotation.hamiltonProduct(Vec3f.POSITIVE_Y.getDegreesQuaternion(effect.getPitch()));
|
||||
rotation.hamiltonProduct(Vec3f.POSITIVE_X.getDegreesQuaternion(180 - effect.getYaw()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(int key, Object value) {
|
||||
public void setAttribute(int key, Number value) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
Unicopia.id("textures/particles/runes_5.png")
|
||||
};
|
||||
|
||||
protected float targetSize = 3;
|
||||
|
||||
protected float prevBaseSize = 0;
|
||||
protected float baseSize = 0;
|
||||
|
||||
|
@ -61,22 +63,31 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
velocityY = 0;
|
||||
velocityZ = 0;
|
||||
Vec3d pos = link.get().map(Caster::getOriginVector).orElse(Vec3d.ZERO);
|
||||
setPos(pos.x, pos.y, pos.z);
|
||||
setPos(pos.x, pos.y + 0.25, pos.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
link = Optional.empty();
|
||||
if (targetSize > 1) {
|
||||
this.targetSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(int key, Object value) {
|
||||
public void setAttribute(int key, Number value) {
|
||||
if (key == ATTR_COLOR) {
|
||||
int tint = (int)value;
|
||||
int tint = value.intValue();
|
||||
red = Color.r(tint);
|
||||
green = Color.g(tint);
|
||||
blue = Color.b(tint);
|
||||
}
|
||||
if (key == ATTR_OPACITY) {
|
||||
alpha = value.floatValue();
|
||||
}
|
||||
if (key == ATTR_RADIUS) {
|
||||
targetSize = value.floatValue();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public float getScale(float tickDelta) {
|
||||
|
@ -137,6 +148,8 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
renderQuad(te, buffer, corners, alpha, tickDelta);
|
||||
}
|
||||
}
|
||||
|
||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,8 +166,11 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
}, this::detach);
|
||||
|
||||
prevBaseSize = baseSize;
|
||||
if (baseSize < 3) {
|
||||
baseSize++;
|
||||
if (baseSize < targetSize) {
|
||||
baseSize += 0.1F;
|
||||
}
|
||||
if (baseSize > targetSize) {
|
||||
baseSize -= 0.1F;
|
||||
}
|
||||
|
||||
rotationAngle = (rotationAngle + 0.3F) % 360;
|
||||
|
|
|
@ -74,20 +74,20 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(int key, Object value) {
|
||||
public void setAttribute(int key, Number value) {
|
||||
if (key == ATTR_RADIUS) {
|
||||
toRadius = (float)value;
|
||||
toRadius = value.floatValue();
|
||||
steps = 20;
|
||||
lerpIncrement = (toRadius - radius) / steps;
|
||||
}
|
||||
if (key == ATTR_COLOR) {
|
||||
int tint = (int)value;
|
||||
int tint = value.intValue();
|
||||
red = Color.r(tint);
|
||||
green = Color.g(tint);
|
||||
blue = Color.b(tint);
|
||||
}
|
||||
if (key == ATTR_OPACITY) {
|
||||
alpha = (float)value;
|
||||
alpha = value.floatValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public class EntityReference<T extends Entity> implements NbtSerialisable {
|
|||
fromNBT(nbt);
|
||||
}
|
||||
|
||||
public void copyFrom(EntityReference<T> other) {
|
||||
public void copyFrom(EntityReference<? extends T> other) {
|
||||
uuid = other.uuid;
|
||||
clientId = other.clientId;
|
||||
pos = other.pos;
|
||||
|
|
|
@ -95,7 +95,7 @@ public class ParticleHandle {
|
|||
|
||||
void detach();
|
||||
|
||||
void setAttribute(int key, Object value);
|
||||
void setAttribute(int key, Number value);
|
||||
}
|
||||
|
||||
public static final class Link {
|
||||
|
|
|
@ -60,6 +60,10 @@ public class SphereParticleEffect implements ParticleEffect {
|
|||
return offset;
|
||||
}
|
||||
|
||||
public void setOffset(Vec3d offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public Vec3f getColor() {
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -152,7 +152,9 @@
|
|||
"spell.unicopia.vortex.lore": "Creates a magnetic force that pulls in other targets",
|
||||
"spell.unicopia.dark_vortex": "Dark Vortex",
|
||||
"spell.unicopia.dark_vortex.lore": "Creates a black hole from which nothing can escape",
|
||||
"spell.unicopia.portal": "Teleportation",
|
||||
"spell.unicopia.displacement": "Displacement",
|
||||
"spell.unicopia.displacement.lore": "Swaps the caster's locatin with that of another entity",
|
||||
"spell.unicopia.portal": "Arcane Rift",
|
||||
"spell.unicopia.portal.lore": "Connects two points in space for fast travel between",
|
||||
"spell.unicopia.necromancy": "Necromancy",
|
||||
"spell.unicopia.necromancy.lore": "Summons undead minions from beyond the grave",
|
||||
|
|
Loading…
Reference in a new issue