mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Rewrite changeling ability to apply over time. Closes #312
This commit is contained in:
parent
3bab3c4f56
commit
e65838b943
6 changed files with 202 additions and 104 deletions
|
@ -2,26 +2,22 @@ package com.minelittlepony.unicopia.ability;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.USounds;
|
import com.minelittlepony.unicopia.USounds;
|
||||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
|
||||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
|
||||||
import com.minelittlepony.unicopia.particle.UParticles;
|
|
||||||
import com.minelittlepony.unicopia.util.TraceHelper;
|
import com.minelittlepony.unicopia.util.TraceHelper;
|
||||||
import com.minelittlepony.unicopia.util.VecHelper;
|
import com.minelittlepony.unicopia.util.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.damage.DamageSource;
|
|
||||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
|
||||||
import net.minecraft.entity.effect.StatusEffects;
|
|
||||||
import net.minecraft.entity.mob.HostileEntity;
|
import net.minecraft.entity.mob.HostileEntity;
|
||||||
import net.minecraft.entity.passive.CowEntity;
|
import net.minecraft.entity.passive.CowEntity;
|
||||||
import net.minecraft.entity.passive.MerchantEntity;
|
import net.minecraft.entity.passive.MerchantEntity;
|
||||||
|
@ -34,6 +30,13 @@ import net.minecraft.particle.ParticleTypes;
|
||||||
* Changeling ability to restore health from mobs
|
* Changeling ability to restore health from mobs
|
||||||
*/
|
*/
|
||||||
public class ChangelingFeedAbility implements Ability<Hit> {
|
public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
|
private static final Predicate<Entity> TARGET_PREDICATE = e -> (e instanceof LivingEntity)
|
||||||
|
&& (e instanceof CowEntity
|
||||||
|
|| e instanceof MerchantEntity
|
||||||
|
|| e instanceof PlayerEntity
|
||||||
|
|| e instanceof SheepEntity
|
||||||
|
|| e instanceof PigEntity
|
||||||
|
|| e instanceof HostileEntity);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWarmupTime(Pony player) {
|
public int getWarmupTime(Pony player) {
|
||||||
|
@ -42,7 +45,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCooldownTime(Pony player) {
|
public int getCooldownTime(Pony player) {
|
||||||
return canFeed(player) ? 15 : 80;
|
return !SpellType.FEED.isOn(player) && ChangelingFeedingSpell.canFeed(player) ? 15 : 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,22 +56,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Optional<Hit> prepare(Pony player) {
|
public Optional<Hit> prepare(Pony player) {
|
||||||
return Hit.of(canFeed(player) && !getTargets(player).isEmpty());
|
return Hit.of(ChangelingFeedingSpell.canFeed(player) && !getTargets(player).findAny().isEmpty());
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canFeed(Pony player) {
|
|
||||||
return player.asEntity().getHealth() < player.asEntity().getMaxHealth()
|
|
||||||
|| player.asEntity().canConsume(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canDrain(Entity e) {
|
|
||||||
return (e instanceof LivingEntity)
|
|
||||||
&& (e instanceof CowEntity
|
|
||||||
|| e instanceof MerchantEntity
|
|
||||||
|| e instanceof PlayerEntity
|
|
||||||
|| e instanceof SheepEntity
|
|
||||||
|| e instanceof PigEntity
|
|
||||||
|| e instanceof HostileEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,16 +64,6 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
return Hit.SERIALIZER;
|
return Hit.SERIALIZER;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<LivingEntity> getTargets(Pony player) {
|
|
||||||
List<Entity> list = VecHelper.findInRange(player.asEntity(), player.asWorld(), player.getOriginVector(), 3, this::canDrain);
|
|
||||||
|
|
||||||
TraceHelper.<LivingEntity>findEntity(player.asEntity(), 17, 1,
|
|
||||||
looked -> looked instanceof LivingEntity && !list.contains(looked) && canDrain(looked))
|
|
||||||
.ifPresent(list::add);
|
|
||||||
|
|
||||||
return list.stream().map(i -> (LivingEntity)i).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCostEstimate(Pony player) {
|
public double getCostEstimate(Pony player) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -93,7 +71,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Pony iplayer, Hit data) {
|
public boolean apply(Pony iplayer, Hit data) {
|
||||||
if (!canFeed(iplayer)) {
|
if (!ChangelingFeedingSpell.canFeed(iplayer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,64 +81,25 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
||||||
int maximumFoodGain = player.canConsume(false) ? (20 - player.getHungerManager().getFoodLevel()) : 0;
|
int maximumFoodGain = player.canConsume(false) ? (20 - player.getHungerManager().getFoodLevel()) : 0;
|
||||||
|
|
||||||
if (maximumHealthGain > 0 || maximumFoodGain > 0) {
|
if (maximumHealthGain > 0 || maximumFoodGain > 0) {
|
||||||
|
List<LivingEntity> targets = getTargets(iplayer).map(LivingEntity.class::cast).toList();
|
||||||
|
|
||||||
float healAmount = 0;
|
if (targets.size() > 0) {
|
||||||
|
new ChangelingFeedingSpell(targets, maximumHealthGain, maximumFoodGain).apply(iplayer);
|
||||||
|
|
||||||
for (LivingEntity i : getTargets(iplayer)) {
|
iplayer.playSound(USounds.ENTITY_PLAYER_CHANGELING_FEED, 0.1F, iplayer.getRandomPitch());
|
||||||
healAmount += drainFrom(iplayer, i);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int foodAmount = (int)Math.floor(Math.min(healAmount / 3, maximumFoodGain));
|
|
||||||
|
|
||||||
if (foodAmount > 0) {
|
|
||||||
healAmount -= foodAmount;
|
|
||||||
}
|
|
||||||
player.getHungerManager().add(Math.max(1, foodAmount), 0.125f);
|
|
||||||
|
|
||||||
player.heal(Math.max(1, Math.min(healAmount, maximumHealthGain)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!canFeed(iplayer)) {
|
|
||||||
iplayer.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
|
|
||||||
} else {
|
|
||||||
iplayer.playSound(USounds.ENTITY_PLAYER_CHANGELING_FEED, 0.1F, iplayer.getRandomPitch());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iplayer.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float drainFrom(Pony changeling, LivingEntity living) {
|
protected Stream<Entity> getTargets(Pony player) {
|
||||||
|
return Stream.concat(
|
||||||
DamageSource d = changeling.damageOf(UDamageTypes.LOVE_DRAINING, changeling);
|
VecHelper.findInRange(player.asEntity(), player.asWorld(), player.getOriginVector(), 3, TARGET_PREDICATE).stream(),
|
||||||
|
TraceHelper.findEntity(player.asEntity(), 17, 1, TARGET_PREDICATE).stream()
|
||||||
float damage = living.getHealth()/2;
|
).distinct();
|
||||||
|
|
||||||
if (damage > 0) {
|
|
||||||
living.damage(d, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParticleUtils.spawnParticles(UParticles.CHANGELING_MAGIC, living, 7);
|
|
||||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, changeling.asEntity(), 0.2F), living, 1);
|
|
||||||
|
|
||||||
if (changeling.asEntity().hasStatusEffect(StatusEffects.NAUSEA)) {
|
|
||||||
StatusEffectInstance effect = changeling.asEntity().getStatusEffect(StatusEffects.NAUSEA);
|
|
||||||
changeling.asEntity().removeStatusEffect(StatusEffects.NAUSEA);
|
|
||||||
living.addStatusEffect(effect);
|
|
||||||
} else if (changeling.asWorld().random.nextInt(2300) == 0) {
|
|
||||||
living.addStatusEffect(new StatusEffectInstance(StatusEffects.WITHER, 20, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (living instanceof PlayerEntity) {
|
|
||||||
damage ++;
|
|
||||||
damage *= 1.6F;
|
|
||||||
|
|
||||||
if (!changeling.asEntity().hasStatusEffect(StatusEffects.HEALTH_BOOST)) {
|
|
||||||
changeling.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HEALTH_BOOST, 13000, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return damage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.USounds;
|
||||||
|
import com.minelittlepony.unicopia.ability.Abilities;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
|
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||||
|
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||||
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||||
|
import net.minecraft.entity.effect.StatusEffects;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.nbt.NbtElement;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
public class ChangelingFeedingSpell extends AbstractSpell {
|
||||||
|
private List<EntityReference<LivingEntity>> targets = List.of();
|
||||||
|
private int nextTargetIndex;
|
||||||
|
|
||||||
|
private float healthToDrain;
|
||||||
|
private int foodToDrain;
|
||||||
|
|
||||||
|
private float damageThisTick;
|
||||||
|
|
||||||
|
public ChangelingFeedingSpell(CustomisedSpellType<?> type) {
|
||||||
|
super(type);
|
||||||
|
setHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangelingFeedingSpell(List<LivingEntity> feedTarget, float healthToDrain, int foodToDrain) {
|
||||||
|
this(SpellType.FEED.withTraits());
|
||||||
|
this.targets = feedTarget.stream().map(EntityReference::new).collect(Collectors.toList() /* make mutable */);
|
||||||
|
this.healthToDrain = healthToDrain;
|
||||||
|
this.foodToDrain = foodToDrain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
|
if (!(source instanceof Pony changeling) || situation != Situation.BODY || !source.canUse(Abilities.FEED)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerEntity player = changeling.asEntity();
|
||||||
|
if (!canFeed(changeling)) {
|
||||||
|
changeling.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float tickDrain = Math.min(0.05F, healthToDrain);
|
||||||
|
damageThisTick += tickDrain;
|
||||||
|
|
||||||
|
if (damageThisTick > 1) {
|
||||||
|
damageThisTick--;
|
||||||
|
|
||||||
|
float healAmount = drain(changeling, 1);
|
||||||
|
float foodAmount = Math.min(healAmount / 3F, foodToDrain);
|
||||||
|
if (foodAmount > 0) {
|
||||||
|
healAmount -= foodAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
foodAmount = MathHelper.clamp(foodAmount, 0, foodToDrain);
|
||||||
|
healAmount = MathHelper.clamp(healAmount, 0, healthToDrain);
|
||||||
|
|
||||||
|
int shanks = MathHelper.floor(foodAmount);
|
||||||
|
player.getHungerManager().add(shanks, foodAmount - shanks);
|
||||||
|
player.heal(healAmount);
|
||||||
|
|
||||||
|
if (!canFeed(changeling)) {
|
||||||
|
changeling.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
|
||||||
|
} else {
|
||||||
|
changeling.playSound(USounds.ENTITY_PLAYER_CHANGELING_FEED, 0.1F, changeling.getRandomPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
foodToDrain -= foodAmount;
|
||||||
|
healthToDrain -= healAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !targets.isEmpty() && (healthToDrain > 0 || foodToDrain > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float drain(Pony changeling, float max) {
|
||||||
|
List<EntityReference<LivingEntity>> targets = this.targets;
|
||||||
|
while (!targets.isEmpty()) {
|
||||||
|
int index = MathHelper.clamp(nextTargetIndex, 0, targets.size());
|
||||||
|
LivingEntity l = targets.get(index).getOrEmpty(changeling.asWorld()).orElse(null);
|
||||||
|
if (l != null && !l.isRemoved() && l.distanceTo(changeling.asEntity()) < 4) {
|
||||||
|
nextTargetIndex = (nextTargetIndex + 1) % targets.size();
|
||||||
|
return drainFrom(changeling, l, max);
|
||||||
|
} else {
|
||||||
|
targets.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float drainFrom(Pony changeling, LivingEntity living, float damage) {
|
||||||
|
DamageSource d = changeling.damageOf(UDamageTypes.LOVE_DRAINING, changeling);
|
||||||
|
|
||||||
|
if (damage > 0) {
|
||||||
|
living.damage(d, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleUtils.spawnParticles(UParticles.CHANGELING_MAGIC, living, 7);
|
||||||
|
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, changeling.asEntity(), 0.2F), living, 1);
|
||||||
|
|
||||||
|
if (changeling.asEntity().hasStatusEffect(StatusEffects.NAUSEA)) {
|
||||||
|
StatusEffectInstance effect = changeling.asEntity().getStatusEffect(StatusEffects.NAUSEA);
|
||||||
|
changeling.asEntity().removeStatusEffect(StatusEffects.NAUSEA);
|
||||||
|
living.addStatusEffect(effect);
|
||||||
|
} else if (changeling.asWorld().random.nextInt(2300) == 0) {
|
||||||
|
living.addStatusEffect(new StatusEffectInstance(StatusEffects.WITHER, 20, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (living instanceof PlayerEntity) {
|
||||||
|
damage ++;
|
||||||
|
damage *= 1.6F;
|
||||||
|
|
||||||
|
if (!changeling.asEntity().hasStatusEffect(StatusEffects.HEALTH_BOOST)) {
|
||||||
|
changeling.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HEALTH_BOOST, 13000, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canFeed(Pony player) {
|
||||||
|
return player.asEntity().getHealth() < player.asEntity().getMaxHealth()
|
||||||
|
|| player.asEntity().canConsume(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toNBT(NbtCompound compound) {
|
||||||
|
super.toNBT(compound);
|
||||||
|
compound.putFloat("healthToDrain", healthToDrain);
|
||||||
|
compound.putInt("foodToDrain", foodToDrain);
|
||||||
|
compound.putFloat("damageThisTick", damageThisTick);
|
||||||
|
compound.put("targets", EntityReference.<LivingEntity>getSerializer().writeAll(targets));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromNBT(NbtCompound compound) {
|
||||||
|
super.fromNBT(compound);
|
||||||
|
healthToDrain = compound.getFloat("healthToDrain");
|
||||||
|
foodToDrain = compound.getInt("foodToDrain");
|
||||||
|
damageThisTick = compound.getFloat("damageThisTick");
|
||||||
|
targets = compound.contains("targets", NbtElement.LIST_TYPE)
|
||||||
|
? EntityReference.<LivingEntity>getSerializer().readAll(compound.getList("targets", NbtElement.COMPOUND_TYPE)).toList()
|
||||||
|
: List.of();
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.Affinity;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||||
|
@ -49,6 +50,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
||||||
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, ThrowableSpell::new);
|
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, ThrowableSpell::new);
|
||||||
|
|
||||||
public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new);
|
public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new);
|
||||||
|
public static final SpellType<ChangelingFeedingSpell> FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, SpellTraits.EMPTY, ChangelingFeedingSpell::new);
|
||||||
public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new);
|
public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new);
|
||||||
public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new);
|
public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new);
|
||||||
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new);
|
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new);
|
||||||
|
|
|
@ -11,7 +11,6 @@ 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.Levelled;
|
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
||||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
@ -31,6 +30,13 @@ import net.minecraft.world.World;
|
||||||
* @param <T> The type of the entity this reference points to.
|
* @param <T> The type of the entity this reference points to.
|
||||||
*/
|
*/
|
||||||
public class EntityReference<T extends Entity> implements NbtSerialisable {
|
public class EntityReference<T extends Entity> implements NbtSerialisable {
|
||||||
|
private static final Serializer<?> SERIALIZER = Serializer.of(EntityReference::new);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Entity> Serializer<EntityReference<T>> getSerializer() {
|
||||||
|
return (Serializer<EntityReference<T>>)SERIALIZER;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private EntityValues<T> reference;
|
private EntityValues<T> reference;
|
||||||
|
|
||||||
|
|
|
@ -128,9 +128,9 @@ public class CrystalHeartItem extends Item implements FloatingArtefactEntity.Art
|
||||||
LivingEntity living = (LivingEntity)e;
|
LivingEntity living = (LivingEntity)e;
|
||||||
|
|
||||||
if (e instanceof PlayerEntity
|
if (e instanceof PlayerEntity
|
||||||
|| (living instanceof TameableEntity && ((TameableEntity)living).isTamed())
|
|| (e instanceof TameableEntity t && t.isTamed())
|
||||||
|| (living instanceof Saddleable && ((Saddleable)living).isSaddled())
|
|| (e instanceof Saddleable s && s.isSaddled())
|
||||||
|| (living instanceof MerchantEntity)) {
|
|| (e instanceof MerchantEntity)) {
|
||||||
if (living.getHealth() < living.getMaxHealth()) {
|
if (living.getHealth() < living.getMaxHealth()) {
|
||||||
outputs.add(living);
|
outputs.add(living);
|
||||||
}
|
}
|
||||||
|
@ -149,19 +149,8 @@ public class CrystalHeartItem extends Item implements FloatingArtefactEntity.Art
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float gives;
|
float gives = supply > demand ? supply / demand : 1;
|
||||||
float takes;
|
float takes = demand > supply ? demand / supply : 1;
|
||||||
|
|
||||||
if (supply > demand) {
|
|
||||||
gives = supply / demand;
|
|
||||||
takes = 1;
|
|
||||||
} else if (demand > supply) {
|
|
||||||
takes = demand / supply;
|
|
||||||
gives = 1;
|
|
||||||
} else {
|
|
||||||
gives = 1;
|
|
||||||
takes = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.forEach(input -> {
|
inputs.forEach(input -> {
|
||||||
input.damage(entity.damageOf(UDamageTypes.LIFE_DRAINING), takes);
|
input.damage(entity.damageOf(UDamageTypes.LIFE_DRAINING), takes);
|
||||||
|
|
|
@ -97,7 +97,7 @@ public interface NbtSerialisable {
|
||||||
return read((NbtCompound)element);
|
return read((NbtCompound)element);
|
||||||
}
|
}
|
||||||
|
|
||||||
default NbtList writeAll(Collection<T> ts) {
|
default NbtList writeAll(Collection<? extends T> ts) {
|
||||||
NbtList list = new NbtList();
|
NbtList list = new NbtList();
|
||||||
ts.stream().map(this::write).forEach(list::add);
|
ts.stream().map(this::write).forEach(list::add);
|
||||||
return list;
|
return list;
|
||||||
|
|
Loading…
Reference in a new issue