mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-12-01 00:37:59 +01:00
Added a homing ability to the firebolt spell
This commit is contained in:
parent
de6f9a92d4
commit
fb6031b89f
11 changed files with 170 additions and 107 deletions
|
@ -6,14 +6,18 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.item.AmuletItem;
|
import com.minelittlepony.unicopia.item.AmuletItem;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
||||||
import com.minelittlepony.unicopia.util.VecHelper;
|
import com.minelittlepony.unicopia.util.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.particle.ParticleTypes;
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.sound.SoundCategory;
|
import net.minecraft.sound.SoundCategory;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
|
@ -97,10 +101,14 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
||||||
boolean remove = player.getSpellSlot().removeIf(spell, true);
|
boolean remove = player.getSpellSlot().removeIf(spell, true);
|
||||||
player.subtractEnergyCost(remove ? 2 : 4);
|
player.subtractEnergyCost(remove ? 2 : 4);
|
||||||
if (!remove) {
|
if (!remove) {
|
||||||
if (spell.apply(player) == null) {
|
Spell s = spell.apply(player);
|
||||||
|
if (s == null) {
|
||||||
player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6);
|
player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6);
|
||||||
player.playSound(SoundEvents.ENTITY_ITEM_BREAK, 1, 0.5F);
|
player.playSound(SoundEvents.ENTITY_ITEM_BREAK, 1, 0.5F);
|
||||||
} else {
|
} else {
|
||||||
|
if (s instanceof HomingSpell) {
|
||||||
|
RayTraceHelper.doTrace(player.getMaster(), 600, 1, EntityPredicates.EXCEPT_SPECTATOR).getEntity().ifPresent(((HomingSpell)s)::setTarget);
|
||||||
|
}
|
||||||
player.playSound(SoundEvents.BLOCK_BEACON_POWER_SELECT, 0.05F, 2.2F);
|
player.playSound(SoundEvents.BLOCK_BEACON_POWER_SELECT, 0.05F, 2.2F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,14 @@ package com.minelittlepony.unicopia.ability;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
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;
|
||||||
|
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
||||||
|
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
@ -61,7 +65,16 @@ public class UnicornProjectileAbility implements Ability<Hit> {
|
||||||
|
|
||||||
if (thrown.getResult() != ActionResult.FAIL) {
|
if (thrown.getResult() != ActionResult.FAIL) {
|
||||||
player.subtractEnergyCost(getCostEstimate(player));
|
player.subtractEnergyCost(getCostEstimate(player));
|
||||||
thrown.getValue().create().toThrowable().throwProjectile(player);
|
|
||||||
|
Spell spell = thrown.getValue().create();
|
||||||
|
|
||||||
|
spell.toThrowable().throwProjectile(player).ifPresent(projectile -> {
|
||||||
|
if (spell instanceof HomingSpell) {
|
||||||
|
RayTraceHelper.doTrace(player.getMaster(), 600, 1, EntityPredicates.EXCEPT_SPECTATOR).getEntity().filter(((HomingSpell)spell)::setTarget).ifPresent(target -> {
|
||||||
|
projectile.setHomingTarget(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A spell that's capable of homing in on a pre-defined target.
|
||||||
|
*/
|
||||||
|
public interface HomingSpell extends Spell {
|
||||||
|
boolean setTarget(Entity target);
|
||||||
|
}
|
|
@ -40,6 +40,15 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
|
||||||
* Returns the resulting projectile entity for customization (or null if on the client).
|
* Returns the resulting projectile entity for customization (or null if on the client).
|
||||||
*/
|
*/
|
||||||
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster) {
|
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster) {
|
||||||
|
return throwProjectile(caster, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projects this spell.
|
||||||
|
*
|
||||||
|
* Returns the resulting projectile entity for customization (or null if on the client).
|
||||||
|
*/
|
||||||
|
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster, float divergance) {
|
||||||
World world = caster.getWorld();
|
World world = caster.getWorld();
|
||||||
|
|
||||||
LivingEntity entity = caster.getMaster();
|
LivingEntity entity = caster.getMaster();
|
||||||
|
@ -51,7 +60,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
|
||||||
|
|
||||||
projectile.setItem(GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), spell.getType()));
|
projectile.setItem(GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), spell.getType()));
|
||||||
projectile.getSpellSlot().put(this);
|
projectile.getSpellSlot().put(this);
|
||||||
projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1);
|
projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, divergance);
|
||||||
projectile.setHydrophobic();
|
projectile.setHydrophobic();
|
||||||
configureProjectile(projectile, caster);
|
configureProjectile(projectile, caster);
|
||||||
world.spawnEntity(projectile);
|
world.spawnEntity(projectile);
|
||||||
|
|
|
@ -1,21 +1,35 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.item.Items;
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
|
||||||
public class FireBoltSpell extends AbstractSpell implements ProjectileSpell {
|
public class FireBoltSpell extends AbstractSpell implements ProjectileSpell, HomingSpell {
|
||||||
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||||
.with(Trait.FIRE, 90)
|
.with(Trait.FOCUS, 10)
|
||||||
.with(Trait.AIR, 60)
|
.with(Trait.CHAOS, 1)
|
||||||
|
.with(Trait.STRENGTH, 11)
|
||||||
|
.with(Trait.FIRE, 60)
|
||||||
.build();
|
.build();
|
||||||
|
public static final SpellTraits HOMING_TRAITS = new SpellTraits.Builder()
|
||||||
|
.with(Trait.FOCUS, 50)
|
||||||
|
.with(Trait.CHAOS, 10)
|
||||||
|
.with(Trait.STRENGTH, 11)
|
||||||
|
.with(Trait.FIRE, 60)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Entity target;
|
||||||
|
|
||||||
protected FireBoltSpell(SpellType<?> type, SpellTraits traits) {
|
protected FireBoltSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
super(type, traits);
|
super(type, traits);
|
||||||
|
@ -29,11 +43,30 @@ public class FireBoltSpell extends AbstractSpell implements ProjectileSpell {
|
||||||
@Override
|
@Override
|
||||||
public boolean tick(Caster<?> caster, Situation situation) {
|
public boolean tick(Caster<?> caster, Situation situation) {
|
||||||
if (situation == Situation.PROJECTILE) {
|
if (situation == Situation.PROJECTILE) {
|
||||||
|
if (caster instanceof MagicProjectileEntity && getTraits().get(Trait.FOCUS) >= 50) {
|
||||||
|
caster.findAllEntitiesInRange(
|
||||||
|
getTraits().get(Trait.FOCUS) - 49,
|
||||||
|
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.notOwnerOrFriend(this, caster))
|
||||||
|
).findFirst().ifPresent(target -> {
|
||||||
|
((MagicProjectileEntity)caster).setHomingTarget(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getTraits().get(Trait.FOCUS) >= 50 && target == null) {
|
||||||
|
target = caster.findAllEntitiesInRange(
|
||||||
|
getTraits().get(Trait.FOCUS) - 49,
|
||||||
|
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.notOwnerOrFriend(this, caster))
|
||||||
|
).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < getNumberOfBalls(caster); i++) {
|
for (int i = 0; i < getNumberOfBalls(caster); i++) {
|
||||||
getType().create(getTraits()).toThrowable().throwProjectile(caster);
|
getType().create(getTraits()).toThrowable().throwProjectile(caster, 2).ifPresent(c -> {
|
||||||
|
c.setHomingTarget(target);
|
||||||
|
});
|
||||||
|
|
||||||
caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 0.7F, 0.4F / (caster.getWorld().random.nextFloat() * 0.4F + 0.8F));
|
caster.playSound(SoundEvents.ENTITY_BLAZE_SHOOT, 0.7F, 0.4F / (caster.getWorld().random.nextFloat() * 0.4F + 0.8F));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -42,12 +75,21 @@ public class FireBoltSpell extends AbstractSpell implements ProjectileSpell {
|
||||||
@Override
|
@Override
|
||||||
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
|
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
|
||||||
projectile.setItem(Items.FIRE_CHARGE.getDefaultStack());
|
projectile.setItem(Items.FIRE_CHARGE.getDefaultStack());
|
||||||
projectile.addThrowDamage(getTraits().get(Trait.FIRE) / 10F);
|
projectile.addThrowDamage(getTraits().get(Trait.POWER, 0, getTraits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F);
|
||||||
projectile.setFireTicks(900000);
|
projectile.setFireTicks(900000);
|
||||||
projectile.setVelocity(projectile.getVelocity().multiply(1.3 + getTraits().get(Trait.STRENGTH)));
|
projectile.setVelocity(projectile.getVelocity().multiply(1.3 + getTraits().get(Trait.STRENGTH) / 11F));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getNumberOfBalls(Caster<?> caster) {
|
protected int getNumberOfBalls(Caster<?> caster) {
|
||||||
return 1 + caster.getWorld().random.nextInt(3) + (int)getTraits().get(Trait.POWER) * 3;
|
return 1 + caster.getWorld().random.nextInt(3) + (int)getTraits().get(Trait.EARTH) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setTarget(Entity target) {
|
||||||
|
if (getTraits().get(Trait.FOCUS) >= 50) {
|
||||||
|
this.target = target;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
|
@ -54,6 +55,20 @@ public class TargetSelecter {
|
||||||
return targets.values().stream().filter(Target::canHurt).count();
|
return targets.values().stream().filter(Target::canHurt).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Predicate<Entity> notOwnerOrFriend(Spell spell, Caster<?> source) {
|
||||||
|
Entity owner = source.getMaster();
|
||||||
|
|
||||||
|
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner));
|
||||||
|
|
||||||
|
if (!ownerIsValid) {
|
||||||
|
return e -> true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity -> {
|
||||||
|
return !ownerIsValid || !(Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity) || FriendshipBraceletItem.isComrade(source, entity));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static final class Target {
|
static final class Target {
|
||||||
private int cooldown = 20;
|
private int cooldown = 20;
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,19 @@ package com.minelittlepony.unicopia.client.particle;
|
||||||
import net.minecraft.client.particle.SpriteProvider;
|
import net.minecraft.client.particle.SpriteProvider;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.particle.ParticleEffect;
|
import net.minecraft.particle.ParticleEffect;
|
||||||
|
import net.minecraft.util.math.Vec3f;
|
||||||
|
|
||||||
public class ChangelingMagicParticle extends MagicParticle {
|
public class ChangelingMagicParticle extends MagicParticle {
|
||||||
|
|
||||||
private final SpriteProvider provider;
|
private final SpriteProvider provider;
|
||||||
|
|
||||||
public ChangelingMagicParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double dx, double dy, double dz) {
|
public ChangelingMagicParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double dx, double dy, double dz) {
|
||||||
super(effect, provider, world, x, y, z, dx, dy, dz, 1, 1, 1);
|
super(effect, provider, world, x, y, z, dx, dy, dz, nextColor(world.random.nextFloat() * 0.6F + 0.4F), 1);
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
float intensity = random.nextFloat() * 0.6F + 0.4F;
|
static Vec3f nextColor(float intensity) {
|
||||||
|
return new Vec3f(intensity * 0.5F, intensity, intensity * 0.4F);
|
||||||
colorRed = intensity * 0.5F;
|
|
||||||
colorGreen = intensity;
|
|
||||||
colorBlue = intensity * 0.4f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -7,13 +7,14 @@ import net.minecraft.client.particle.SpriteBillboardParticle;
|
||||||
import net.minecraft.client.particle.SpriteProvider;
|
import net.minecraft.client.particle.SpriteProvider;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.particle.ParticleEffect;
|
import net.minecraft.particle.ParticleEffect;
|
||||||
|
import net.minecraft.util.math.Vec3f;
|
||||||
|
|
||||||
public class MagicParticle extends SpriteBillboardParticle {
|
public class MagicParticle extends SpriteBillboardParticle {
|
||||||
private double startX;
|
private final double startX;
|
||||||
private double startY;
|
private final double startY;
|
||||||
private double startZ;
|
private final double startZ;
|
||||||
|
|
||||||
MagicParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ, float r, float g, float b) {
|
MagicParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ, Vec3f color, float alpha) {
|
||||||
super(w, x, y, z);
|
super(w, x, y, z);
|
||||||
setSprite(provider);
|
setSprite(provider);
|
||||||
|
|
||||||
|
@ -26,41 +27,14 @@ public class MagicParticle extends SpriteBillboardParticle {
|
||||||
scale = random.nextFloat() * 0.12F;
|
scale = random.nextFloat() * 0.12F;
|
||||||
maxAge = (int)(Math.random() * 10) + 20;
|
maxAge = (int)(Math.random() * 10) + 20;
|
||||||
|
|
||||||
colorRed = r;
|
colorRed = color.getX();
|
||||||
colorGreen = g;
|
colorGreen = color.getY();
|
||||||
colorBlue = b;
|
colorBlue = color.getZ();
|
||||||
|
colorAlpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MagicParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
|
public MagicParticle(MagicParticleEffect effect, SpriteProvider provider, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
|
||||||
this(effect, provider, w, x, y, z, vX, vY, vZ, 1, 1, 1);
|
this(effect, provider, w, x, y, z, vX, vY, vZ, effect.getColor(w.random), 0.7F);
|
||||||
|
|
||||||
colorAlpha = 0.7F;
|
|
||||||
colorGreen *= 0.3F;
|
|
||||||
|
|
||||||
if (effect instanceof MagicParticleEffect && ((MagicParticleEffect)effect).hasTint()) {
|
|
||||||
MagicParticleEffect parameters = (MagicParticleEffect)effect;
|
|
||||||
|
|
||||||
colorRed = parameters.getColor().getX();
|
|
||||||
colorGreen = parameters.getColor().getY();
|
|
||||||
colorBlue = parameters.getColor().getZ();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (random.nextBoolean()) {
|
|
||||||
colorBlue *= 0.4F;
|
|
||||||
}
|
|
||||||
if (random.nextBoolean()) {
|
|
||||||
colorRed *= 0.9F;
|
|
||||||
}
|
|
||||||
if (random.nextBoolean()) {
|
|
||||||
colorGreen += 0.5F;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (random.nextBoolean()) {
|
|
||||||
colorGreen *= 2F;
|
|
||||||
} else if (random.nextBoolean()) {
|
|
||||||
colorRed *= 3.9F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,7 +54,7 @@ public class MagicParticle extends SpriteBillboardParticle {
|
||||||
float timer = (float)age / (float)maxAge;
|
float timer = (float)age / (float)maxAge;
|
||||||
|
|
||||||
int v = light >> 16 & 255;
|
int v = light >> 16 & 255;
|
||||||
v = (int)Math.min(v + Math.pow(timer, 4) * 240, 240);
|
v = (int)Math.min(v + (timer * timer * timer * timer) * 240, 240);
|
||||||
|
|
||||||
return (light & 255) | v << 16;
|
return (light & 255) | v << 16;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +69,8 @@ public class MagicParticle extends SpriteBillboardParticle {
|
||||||
markDead();
|
markDead();
|
||||||
} else {
|
} else {
|
||||||
float timer = (float)age / (float)maxAge;
|
float timer = (float)age / (float)maxAge;
|
||||||
timer = 1 + timer - timer * timer * 2;
|
|
||||||
|
timer += 1 - (timer * timer) * 2;
|
||||||
|
|
||||||
x = startX + velocityX * timer;
|
x = startX + velocityX * timer;
|
||||||
y = startY + velocityY;
|
y = startY + velocityY;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.particle;
|
package com.minelittlepony.unicopia.particle;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import com.minelittlepony.common.util.Color;
|
import com.minelittlepony.common.util.Color;
|
||||||
import com.mojang.brigadier.StringReader;
|
import com.mojang.brigadier.StringReader;
|
||||||
|
@ -46,10 +47,24 @@ public class MagicParticleEffect implements ParticleEffect {
|
||||||
return tinted;
|
return tinted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3f getColor() {
|
public Vec3f getColor(Random random) {
|
||||||
|
if (hasTint()) {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float r = random.nextBoolean() ? 0.9F : 1;
|
||||||
|
float g = 0.3F;
|
||||||
|
float b = random.nextBoolean() ? 0.4F : 1;
|
||||||
|
|
||||||
|
if (random.nextBoolean()) {
|
||||||
|
g *= 2F;
|
||||||
|
} else if (random.nextBoolean()) {
|
||||||
|
r *= 3.9F;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vec3f(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParticleType<?> getType() {
|
public ParticleType<?> getType() {
|
||||||
return UParticles.UNICORN_MAGIC;
|
return UParticles.UNICORN_MAGIC;
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.projectile;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Affinity;
|
import com.minelittlepony.unicopia.Affinity;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
@ -12,6 +14,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.EntityPhysics;
|
import com.minelittlepony.unicopia.entity.EntityPhysics;
|
||||||
|
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||||
import com.minelittlepony.unicopia.entity.Physics;
|
import com.minelittlepony.unicopia.entity.Physics;
|
||||||
import com.minelittlepony.unicopia.entity.UEntities;
|
import com.minelittlepony.unicopia.entity.UEntities;
|
||||||
import com.minelittlepony.unicopia.item.UItems;
|
import com.minelittlepony.unicopia.item.UItems;
|
||||||
|
@ -58,6 +61,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
|
|
||||||
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY, false);
|
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY, false);
|
||||||
|
|
||||||
|
private final EntityReference<Entity> homingTarget = new EntityReference<>();
|
||||||
|
|
||||||
public MagicProjectileEntity(EntityType<MagicProjectileEntity> type, World world) {
|
public MagicProjectileEntity(EntityType<MagicProjectileEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
}
|
}
|
||||||
|
@ -94,6 +99,10 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
setOwner(owner);
|
setOwner(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHomingTarget(@Nullable Entity target) {
|
||||||
|
homingTarget.set(target);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LivingEntity getMaster() {
|
public LivingEntity getMaster() {
|
||||||
return (LivingEntity)getOwner();
|
return (LivingEntity)getOwner();
|
||||||
|
@ -146,8 +155,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if (!world.isClient()) {
|
if (!world.isClient() && !homingTarget.isPresent(world)) {
|
||||||
if (Math.abs(getVelocity().x) < 0.01 && Math.abs(getVelocity().x) < 0.01 && Math.abs(getVelocity().y) < 0.01) {
|
if (getVelocity().length() < 0.01) {
|
||||||
discard();
|
discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +184,12 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
setVelocity(new Vec3d(vel.x, velY, vel.z));
|
setVelocity(new Vec3d(vel.x, velY, vel.z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
homingTarget.ifPresent(world, e -> {
|
||||||
|
setNoGravity(true);
|
||||||
|
noClip = true;
|
||||||
|
setVelocity(getVelocity().add(e.getPos().subtract(getPos()).normalize().multiply(0.2)).multiply(0.6, 0.6, 0.6));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParticleEffect getParticleParameters() {
|
private ParticleEffect getParticleParameters() {
|
||||||
|
@ -200,13 +215,13 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
world.addParticle(effect, getX(), getY(), getZ(), 0, 0, 0);
|
world.addParticle(effect, getX(), getY(), getZ(), 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readCustomDataFromNbt(NbtCompound compound) {
|
public void readCustomDataFromNbt(NbtCompound compound) {
|
||||||
super.readCustomDataFromNbt(compound);
|
super.readCustomDataFromNbt(compound);
|
||||||
physics.fromNBT(compound);
|
physics.fromNBT(compound);
|
||||||
|
homingTarget.fromNBT(compound.getCompound("homingTarget"));
|
||||||
if (compound.contains("effect")) {
|
if (compound.contains("effect")) {
|
||||||
getSpellSlot().put(SpellType.fromNBT(compound.getCompound("effect")));
|
getSpellSlot().put(SpellType.fromNBT(compound.getCompound("effect")));
|
||||||
}
|
}
|
||||||
|
@ -216,6 +231,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
public void writeCustomDataToNbt(NbtCompound compound) {
|
public void writeCustomDataToNbt(NbtCompound compound) {
|
||||||
super.writeCustomDataToNbt(compound);
|
super.writeCustomDataToNbt(compound);
|
||||||
physics.toNBT(compound);
|
physics.toNBT(compound);
|
||||||
|
compound.put("homingTarget", homingTarget.toNBT());
|
||||||
getSpellSlot().get(true).ifPresent(effect -> {
|
getSpellSlot().get(true).ifPresent(effect -> {
|
||||||
compound.put("effect", SpellType.toNBT(effect));
|
compound.put("effect", SpellType.toNBT(effect));
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.function.Predicate;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.projectile.ProjectileUtil;
|
||||||
import net.minecraft.predicate.entity.EntityPredicates;
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.util.hit.BlockHitResult;
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
import net.minecraft.util.hit.EntityHitResult;
|
import net.minecraft.util.hit.EntityHitResult;
|
||||||
|
@ -49,58 +50,18 @@ public class RayTraceHelper {
|
||||||
* @return A Trace describing what was found.
|
* @return A Trace describing what was found.
|
||||||
*/
|
*/
|
||||||
public static Trace doTrace(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
|
public static Trace doTrace(Entity e, double distance, float tickDelta, Predicate<Entity> predicate) {
|
||||||
HitResult tracedBlock = e.raycast(distance, tickDelta, false);
|
final Vec3d ray = e.getRotationVec(tickDelta).multiply(distance);
|
||||||
|
|
||||||
final Vec3d start = e.getCameraPosVec(tickDelta);
|
final Vec3d start = e.getCameraPosVec(tickDelta);
|
||||||
|
|
||||||
final double totalTraceDistance = tracedBlock == null ? distance : tracedBlock.getPos().distanceTo(start);
|
final Box box = e.getBoundingBox().stretch(ray).expand(1);
|
||||||
|
|
||||||
final Vec3d ray = e.getRotationVec(tickDelta).multiply(distance);
|
EntityHitResult pointedEntity = ProjectileUtil.raycast(e, start, start.add(ray), box, predicate.and(Entity::collides), distance);
|
||||||
final Vec3d end = start.add(ray);
|
|
||||||
|
|
||||||
Vec3d hit = null;
|
if (pointedEntity != null) {
|
||||||
Entity pointedEntity = null;
|
return new Trace(pointedEntity);
|
||||||
|
|
||||||
double traceDistance = totalTraceDistance;
|
|
||||||
|
|
||||||
for (Entity entity : e.world.getOtherEntities(e,
|
|
||||||
e.getBoundingBox().expand(ray.x + 1, ray.y + 1, ray.z + 1),
|
|
||||||
predicate.and(Entity::collides)
|
|
||||||
)) {
|
|
||||||
Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin());
|
|
||||||
|
|
||||||
Optional<Vec3d> intercept = entityAABB.raycast(start, end);
|
|
||||||
|
|
||||||
if (entityAABB.contains(start)) {
|
|
||||||
if (traceDistance <= 0) {
|
|
||||||
pointedEntity = entity;
|
|
||||||
hit = intercept.orElse(null);
|
|
||||||
traceDistance = 0;
|
|
||||||
}
|
|
||||||
} else if (intercept.isPresent()) {
|
|
||||||
Vec3d inter = intercept.get();
|
|
||||||
double distanceToHit = start.distanceTo(inter);
|
|
||||||
|
|
||||||
if (distanceToHit < traceDistance || traceDistance == 0) {
|
|
||||||
if (entity.getRootVehicle() == e.getRootVehicle()) {
|
|
||||||
if (traceDistance == 0) {
|
|
||||||
pointedEntity = entity;
|
|
||||||
hit = inter;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pointedEntity = entity;
|
|
||||||
hit = inter;
|
|
||||||
traceDistance = distanceToHit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) {
|
return new Trace(e.raycast(distance, tickDelta, false));
|
||||||
return new Trace(new EntityHitResult(pointedEntity, hit));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Trace(tracedBlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Trace {
|
public static class Trace {
|
||||||
|
|
Loading…
Reference in a new issue