mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-17 10:24:23 +01:00
Allow spells to animate post-removal
This commit is contained in:
parent
5356c5c7ec
commit
a19637a8e4
8 changed files with 95 additions and 6 deletions
|
@ -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.SpellContainer.Operation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
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;
|
||||||
|
@ -92,7 +93,11 @@ public class UnicornDispellAbility implements Ability<Pos> {
|
||||||
public boolean apply(Pony player, Pos data) {
|
public boolean apply(Pony player, Pos data) {
|
||||||
player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE);
|
player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE);
|
||||||
Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
|
Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
|
||||||
target.getSpellSlot().clear();
|
target.getSpellSlot().forEach(spell -> {
|
||||||
|
spell.setDead();
|
||||||
|
spell.tickDying(target);
|
||||||
|
return Operation.ofBoolean(!spell.isDead());
|
||||||
|
}, true);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,11 +69,20 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
||||||
getDelegates().forEach(Spell::setDead);
|
getDelegates().forEach(Spell::setDead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickDying(Caster<?> caster) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDead() {
|
public boolean isDead() {
|
||||||
return getDelegates().isEmpty() || getDelegates().stream().allMatch(Spell::isDead);
|
return getDelegates().isEmpty() || getDelegates().stream().allMatch(Spell::isDead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDying() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() {
|
public boolean isDirty() {
|
||||||
return dirty || getDelegates().stream().anyMatch(Spell::isDirty);
|
return dirty || getDelegates().stream().anyMatch(Spell::isDirty);
|
||||||
|
@ -110,7 +119,13 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tick(Caster<?> source, Situation situation) {
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
return execute(getDelegates().stream(), a -> a.tick(source, situation));
|
return execute(getDelegates().stream(), a -> {
|
||||||
|
if (a.isDying()) {
|
||||||
|
a.tickDying(source);
|
||||||
|
return !a.isDead();
|
||||||
|
}
|
||||||
|
return a.tick(source, situation);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -59,6 +59,10 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
||||||
private int prevAge;
|
private int prevAge;
|
||||||
private int age;
|
private int age;
|
||||||
|
|
||||||
|
private boolean dead;
|
||||||
|
private int prevDeathTicks;
|
||||||
|
private int deathTicks;
|
||||||
|
|
||||||
private Optional<Vec3d> position = Optional.empty();
|
private Optional<Vec3d> position = Optional.empty();
|
||||||
|
|
||||||
public PlaceableSpell(CustomisedSpellType<?> type) {
|
public PlaceableSpell(CustomisedSpellType<?> type) {
|
||||||
|
@ -74,6 +78,29 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
||||||
return MathHelper.lerp(tickDelta, prevAge, age);
|
return MathHelper.lerp(tickDelta, prevAge, age);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getScale(float tickDelta) {
|
||||||
|
float add = MathHelper.clamp(getAge(tickDelta) / 25F, 0, 1);
|
||||||
|
float subtract = dead ? 1 - (MathHelper.lerp(tickDelta, prevDeathTicks, deathTicks) / 20F) : 0;
|
||||||
|
return MathHelper.clamp(add - subtract, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDying() {
|
||||||
|
return dead && deathTicks > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDead() {
|
||||||
|
super.setDead();
|
||||||
|
dead = true;
|
||||||
|
deathTicks = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDead() {
|
||||||
|
return dead && deathTicks <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Spell> getDelegates() {
|
public Collection<Spell> getDelegates() {
|
||||||
return List.of(spell);
|
return List.of(spell);
|
||||||
|
@ -119,6 +146,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
||||||
return !isDead();
|
return !isDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickDying(Caster<?> caster) {
|
||||||
|
prevDeathTicks = deathTicks;
|
||||||
|
deathTicks--;
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDetachment(Caster<?> source, EntityValues<?> target) {
|
private void checkDetachment(Caster<?> source, EntityValues<?> target) {
|
||||||
if (getWorld(source).map(Ether::get).map(ether -> ether.get(getType(), target, placedSpellId)).isEmpty()) {
|
if (getWorld(source).map(Ether::get).map(ether -> ether.get(getType(), target, placedSpellId)).isEmpty()) {
|
||||||
setDead();
|
setDead();
|
||||||
|
@ -198,6 +231,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
||||||
@Override
|
@Override
|
||||||
public void toNBT(NbtCompound compound) {
|
public void toNBT(NbtCompound compound) {
|
||||||
super.toNBT(compound);
|
super.toNBT(compound);
|
||||||
|
compound.putBoolean("dead", dead);
|
||||||
|
compound.putInt("deathTicks", deathTicks);
|
||||||
compound.putInt("age", age);
|
compound.putInt("age", age);
|
||||||
compound.putFloat("pitch", pitch);
|
compound.putFloat("pitch", pitch);
|
||||||
compound.putFloat("yaw", yaw);
|
compound.putFloat("yaw", yaw);
|
||||||
|
@ -217,6 +252,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
||||||
@Override
|
@Override
|
||||||
public void fromNBT(NbtCompound compound) {
|
public void fromNBT(NbtCompound compound) {
|
||||||
super.fromNBT(compound);
|
super.fromNBT(compound);
|
||||||
|
dead = compound.getBoolean("dead");
|
||||||
|
deathTicks = compound.getInt("deathTicks");
|
||||||
age = compound.getInt("age");
|
age = compound.getInt("age");
|
||||||
pitch = compound.getFloat("pitch");
|
pitch = compound.getFloat("pitch");
|
||||||
yaw = compound.getFloat("yaw");
|
yaw = compound.getFloat("yaw");
|
||||||
|
|
|
@ -61,6 +61,8 @@ public interface Spell extends NbtSerialisable, Affine {
|
||||||
*/
|
*/
|
||||||
boolean isDead();
|
boolean isDead();
|
||||||
|
|
||||||
|
boolean isDying();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this effect has changes that need to be sent to the client.
|
* Returns true if this effect has changes that need to be sent to the client.
|
||||||
*/
|
*/
|
||||||
|
@ -68,6 +70,7 @@ public interface Spell extends NbtSerialisable, Affine {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this spell to the supplied caster.
|
* Applies this spell to the supplied caster.
|
||||||
|
* @param caster The caster to apply the spell to
|
||||||
*/
|
*/
|
||||||
default boolean apply(Caster<?> caster) {
|
default boolean apply(Caster<?> caster) {
|
||||||
caster.getSpellSlot().put(this);
|
caster.getSpellSlot().put(this);
|
||||||
|
@ -76,7 +79,7 @@ public interface Spell extends NbtSerialisable, Affine {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default form of this spell used to apply to a caster.
|
* Gets the default form of this spell used to apply to a caster.
|
||||||
* @param caster
|
* @param caster The caster currently fueling this spell
|
||||||
*/
|
*/
|
||||||
default Spell prepareForCast(Caster<?> caster, CastingMethod method) {
|
default Spell prepareForCast(Caster<?> caster, CastingMethod method) {
|
||||||
return this;
|
return this;
|
||||||
|
@ -89,6 +92,12 @@ public interface Spell extends NbtSerialisable, Affine {
|
||||||
*/
|
*/
|
||||||
boolean tick(Caster<?> caster, Situation situation);
|
boolean tick(Caster<?> caster, Situation situation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on spells that are actively dying to update any post-death animations before removal.
|
||||||
|
* @param caster The caster currently fueling this spell
|
||||||
|
*/
|
||||||
|
void tickDying(Caster<?> caster);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks this effect as dirty.
|
* Marks this effect as dirty.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,6 +12,7 @@ import net.minecraft.nbt.NbtCompound;
|
||||||
public abstract class AbstractSpell implements Spell {
|
public abstract class AbstractSpell implements Spell {
|
||||||
|
|
||||||
private boolean dead;
|
private boolean dead;
|
||||||
|
private boolean dying;
|
||||||
private boolean dirty;
|
private boolean dirty;
|
||||||
private boolean hidden;
|
private boolean hidden;
|
||||||
private boolean destroyed;
|
private boolean destroyed;
|
||||||
|
@ -45,7 +46,7 @@ public abstract class AbstractSpell implements Spell {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void setDead() {
|
public final void setDead() {
|
||||||
dead = true;
|
dying = true;
|
||||||
setDirty();
|
setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +55,11 @@ public abstract class AbstractSpell implements Spell {
|
||||||
return dead;
|
return dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isDying() {
|
||||||
|
return dying;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isDirty() {
|
public final boolean isDirty() {
|
||||||
return dirty;
|
return dirty;
|
||||||
|
@ -82,6 +88,11 @@ public abstract class AbstractSpell implements Spell {
|
||||||
protected void onDestroyed(Caster<?> caster) {
|
protected void onDestroyed(Caster<?> caster) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tickDying(Caster<?> caster) {
|
||||||
|
dead = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void destroy(Caster<?> caster) {
|
public final void destroy(Caster<?> caster) {
|
||||||
if (destroyed) {
|
if (destroyed) {
|
||||||
|
@ -94,6 +105,7 @@ public abstract class AbstractSpell implements Spell {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toNBT(NbtCompound compound) {
|
public void toNBT(NbtCompound compound) {
|
||||||
|
compound.putBoolean("dying", dying);
|
||||||
compound.putBoolean("dead", dead);
|
compound.putBoolean("dead", dead);
|
||||||
compound.putBoolean("hidden", hidden);
|
compound.putBoolean("hidden", hidden);
|
||||||
compound.putUuid("uuid", uuid);
|
compound.putUuid("uuid", uuid);
|
||||||
|
@ -106,6 +118,7 @@ public abstract class AbstractSpell implements Spell {
|
||||||
if (compound.contains("uuid")) {
|
if (compound.contains("uuid")) {
|
||||||
uuid = compound.getUuid("uuid");
|
uuid = compound.getUuid("uuid");
|
||||||
}
|
}
|
||||||
|
dying = compound.getBoolean("dying");
|
||||||
dead = compound.getBoolean("dead");
|
dead = compound.getBoolean("dead");
|
||||||
hidden = compound.getBoolean("hidden");
|
hidden = compound.getBoolean("hidden");
|
||||||
if (compound.contains("traits")) {
|
if (compound.contains("traits")) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class PlacedSpellRenderer extends SpellRenderer<PlaceableSpell> {
|
||||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
|
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
|
||||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
|
||||||
|
|
||||||
float scale = (spell.getAge(tickDelta) / 25F) * 3;
|
float scale = spell.getScale(tickDelta) * 3;
|
||||||
matrices.scale(scale, scale, scale);
|
matrices.scale(scale, scale, scale);
|
||||||
|
|
||||||
float angle = (animationProgress / 9F) % 360;
|
float angle = (animationProgress / 9F) % 360;
|
||||||
|
|
|
@ -72,6 +72,10 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<CastS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updatePostDeath() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityReference<LivingEntity> getMasterReference() {
|
public EntityReference<LivingEntity> getMasterReference() {
|
||||||
return owner;
|
return owner;
|
||||||
|
|
|
@ -44,7 +44,13 @@ public class EffectSync implements SpellContainer, NbtSerialisable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tick(Situation situation) {
|
public boolean tick(Situation situation) {
|
||||||
return tick(spell -> Operation.ofBoolean(spell.tick(owner, situation)));
|
return tick(spell -> {
|
||||||
|
if (spell.isDying()) {
|
||||||
|
spell.tickDying(owner);
|
||||||
|
return Operation.ofBoolean(!spell.isDead());
|
||||||
|
}
|
||||||
|
return Operation.ofBoolean(spell.tick(owner, situation));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tick(Function<Spell, Operation> tickAction) {
|
public boolean tick(Function<Spell, Operation> tickAction) {
|
||||||
|
|
Loading…
Reference in a new issue