Configure spell attributes for all the spell types

This commit is contained in:
Sollace 2024-06-07 00:15:15 +01:00
parent aaea2bfbc1
commit 92d2bc229f
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
23 changed files with 233 additions and 238 deletions

View file

@ -1,20 +1,15 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import net.minecraft.text.Text;
public abstract class AbstractAreaEffectSpell extends AbstractSpell {
public static void appendRangeTooltip(CustomisedSpellType<?> type, List<Text> tooltip) {
float addedRange = type.traits().get(Trait.POWER);
if (addedRange != 0) {
tooltip.add(SpellAttributes.ofRelative(SpellAttributes.RANGE, addedRange));
}
}
protected static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power));
public static final TooltipFactory TOOLTIP = RANGE;
protected AbstractAreaEffectSpell(CustomisedSpellType<?> type) {
super(type);
@ -24,8 +19,4 @@ public abstract class AbstractAreaEffectSpell extends AbstractSpell {
public Spell prepareForCast(Caster<?> caster, CastingMethod method) {
return toPlaceable();
}
protected final float getAdditionalRange() {
return (int)getTraits().get(Trait.POWER);
}
}

View file

@ -13,14 +13,14 @@ import net.minecraft.util.Util;
public interface SpellAttributes {
Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location"));
Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person"));
Text TARGET_ENTITY = of(Unicopia.id("focused_entity"));
Text FOLLOWS_TARGET = of(Unicopia.id("follows_target"));
Identifier FOLLOWS_TARGET = Unicopia.id("follows_target");
Text PERMIT_ITEMS = of(Unicopia.id("permit_items"));
Text PERMIT_PASSIVE = of(Unicopia.id("permit_passive"));
Text PERMIT_HOSTILE = of(Unicopia.id("permit_hostile"));
Text PERMIT_PLAYER = of(Unicopia.id("permit_player"));
Identifier PERMIT_ITEMS = Unicopia.id("permit_items");
Identifier PERMIT_PASSIVE = Unicopia.id("permit_passive");
Identifier PERMIT_HOSTILE = Unicopia.id("permit_hostile");
Identifier PERMIT_PLAYER = Unicopia.id("permit_player");
Identifier FOCUSED_ENTITY = Unicopia.id("focused_entity");
Identifier RANGE = Unicopia.id("range");
Identifier DURATION = Unicopia.id("duration");
Identifier STRENGTH = Unicopia.id("strength");
@ -38,15 +38,20 @@ public interface SpellAttributes {
Identifier ORB_COUNT = Unicopia.id("orb_count");
Identifier WAVE_SIZE = Unicopia.id("wave_size");
Identifier FOLLOW_RANGE = Unicopia.id("follow_range");
Identifier LIGHT_TARGET = Unicopia.id("light_target");
Identifier STICK_TO_TARGET = Unicopia.id("stick_to_target");
Identifier SOAPINESS = Unicopia.id("soapiness");
Identifier CAST_ON = Unicopia.id("cast_on");
Identifier TARGET_PREFERENCE = Unicopia.id("target_preference");
Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference");
@Deprecated
static Text of(Identifier id) {
return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE);
}
@Deprecated
static Text of(Identifier id, float value) {
return Text.literal(" ").append(
Text.translatable("attribute.modifier.equals.0",
@ -55,10 +60,12 @@ public interface SpellAttributes {
).formatted(Formatting.LIGHT_PURPLE);
}
@Deprecated
static Text ofRelative(Identifier id, float value) {
return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false);
}
@Deprecated
static Text ofTime(Identifier id, long time) {
return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0",
StringHelper.formatTicks((int)Math.abs(time)),
@ -66,6 +73,7 @@ public interface SpellAttributes {
).formatted(Formatting.LIGHT_PURPLE));
}
@Deprecated
public enum ValueType {
REGULAR,
TIME,

View file

@ -1,15 +1,12 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
/**
@ -17,17 +14,10 @@ import net.minecraft.util.math.MathHelper;
*/
public interface TimedSpell extends Spell {
int BASE_DURATION = 120 * 20;
SpellAttribute<Integer> TIME = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> BASE_DURATION + (int)(MathHelper.clamp(focus, 0, 160) * 19) * 20);
Timer getTimer();
static void appendDurationTooltip(CustomisedSpellType<?> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, BASE_DURATION + getExtraDuration(type.traits())));
}
static int getExtraDuration(SpellTraits traits) {
return (int)(traits.get(Trait.FOCUS, 0, 160) * 19) * 20;
}
class Timer implements Tickable, NbtSerialisable {
private int maxDuration;
private int duration;

View file

@ -0,0 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell.attribute;
public enum CastOn {
LOCATION,
SELF
}

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.attribute;
import java.util.List;
import java.util.Locale;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
@ -18,7 +19,7 @@ import net.minecraft.util.Util;
public record SpellAttribute<T> (
Trait trait,
Float2ObjectFunction<T> valueGetter,
BiFunction<SpellTraits, Float, T> valueGetter,
TooltipFactory tooltipFactory
) implements TooltipFactory {
@Override
@ -27,7 +28,11 @@ public record SpellAttribute<T> (
}
public T get(SpellTraits traits) {
return valueGetter.get(traits.get(trait));
return valueGetter.apply(traits, traits.get(trait));
}
public static <T extends Number> SpellAttribute<T> create(Identifier id, AttributeFormat format, Trait trait, BiFunction<SpellTraits, Float, @NotNull T> valueGetter) {
return create(id, format, format, trait, valueGetter, false);
}
public static <T extends Number> SpellAttribute<T> create(Identifier id, AttributeFormat format, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter) {
@ -38,16 +43,24 @@ public record SpellAttribute<T> (
return create(id, baseFormat, relativeFormat, trait, valueGetter, false);
}
public static <T extends Number> SpellAttribute<T> create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction<SpellTraits, Float, @NotNull T> valueGetter) {
return create(id, baseFormat, relativeFormat, trait, valueGetter, false);
}
public static <T extends @NotNull Number> SpellAttribute<T> create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, Float2ObjectFunction<@NotNull T> valueGetter, boolean detrimental) {
return create(id, baseFormat, relativeFormat, trait, (traits, value) -> valueGetter.get(value.floatValue()), detrimental);
}
public static <T extends @NotNull Number> SpellAttribute<T> create(Identifier id, AttributeFormat baseFormat, AttributeFormat relativeFormat, Trait trait, BiFunction<SpellTraits, Float, @NotNull T> valueGetter, boolean detrimental) {
Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id));
return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> {
float traitAmount = type.traits().get(trait);
float traitDifference = type.relativeTraits().get(trait);
float value = valueGetter.get(traitAmount).floatValue();
float value = valueGetter.apply(type.traits(), traitAmount).floatValue();
var b = baseFormat.getBase(name, value, "equals", Formatting.LIGHT_PURPLE);
if (traitDifference != 0) {
tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.get(traitAmount - traitDifference).floatValue(), value, detrimental)));
tooltip.add(b.append(relativeFormat.getRelative(Text.empty(), valueGetter.apply(type.traits(), traitAmount - traitDifference).floatValue(), value, detrimental)));
tooltip.add(AttributeFormat.formatTraitDifference(trait, traitDifference));
} else {
tooltip.add(b);
@ -56,11 +69,15 @@ public record SpellAttribute<T> (
}
public static SpellAttribute<Boolean> createConditional(Identifier id, Trait trait, Float2ObjectFunction<Boolean> valueGetter) {
return createConditional(id, trait, (traits, value) -> valueGetter.get(value.floatValue()));
}
public static SpellAttribute<Boolean> createConditional(Identifier id, Trait trait, BiFunction<SpellTraits, Float, @NotNull Boolean> valueGetter) {
return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> {
Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id));
float difference = type.relativeTraits().get(trait);
Text value = AttributeFormat.formatAttributeLine(name);
if (!valueGetter.get(type.traits().get(trait))) {
if (!valueGetter.apply(type.traits(), type.traits().get(trait))) {
value = value.copy().formatted(Formatting.STRIKETHROUGH, Formatting.DARK_GRAY);
}
tooltip.add(value);
@ -71,9 +88,13 @@ public record SpellAttribute<T> (
}
public static <T extends Enum<T>> SpellAttribute<T> createEnumerated(Identifier id, Trait trait, Float2ObjectFunction<T> valueGetter) {
return createEnumerated(id, trait, (traits, value) -> valueGetter.get(value.floatValue()));
}
public static <T extends Enum<T>> SpellAttribute<T> createEnumerated(Identifier id, Trait trait, BiFunction<SpellTraits, Float, @NotNull T> valueGetter) {
Function<T, Text> cache = Util.memoize(t -> Text.translatable(Util.createTranslationKey("spell_attribute", id.withPath(id.getPath() + "." + t.name().toLowerCase(Locale.ROOT)))));
return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> {
T t = valueGetter.get(type.traits().get(trait));
T t = valueGetter.apply(type.traits(), type.traits().get(trait));
if (t != null) {
int max = t.getClass().getEnumConstants().length;

View file

@ -1,8 +1,10 @@
package com.minelittlepony.unicopia.ability.magic.spell.attribute;
import java.util.List;
import java.util.function.Predicate;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import net.minecraft.text.Text;
@ -16,4 +18,17 @@ public interface TooltipFactory {
}
};
}
static TooltipFactory of(Text line) {
return (type, tooltip) -> tooltip.add(line);
}
default TooltipFactory conditionally(Predicate<SpellTraits> condition) {
TooltipFactory self = this;
return (type, tooltip) -> {
if (condition.test(type.traits())) {
self.appendTooltip(type, tooltip);
}
};
}
}

View file

@ -1,11 +1,10 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.mob.UEntities;
@ -16,7 +15,6 @@ import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.Entity;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
@ -26,11 +24,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell {
.with(Trait.STRENGTH, 30)
.build();
static void appendTooltip(CustomisedSpellType<AreaProtectionSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.CAST_ON_LOCATION);
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER)));
}
static final TooltipFactory TOOLTIP = TooltipFactory.of(TooltipFactory.of(SpellAttributes.CAST_ON_LOCATION), RANGE);
protected AreaProtectionSpell(CustomisedSpellType<?> type) {
super(type);
@ -71,7 +65,7 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell {
private double getRange(Caster<?> source) {
float multiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2;
float min = 4 + getAdditionalRange();
float min = RANGE.get(getTraits());
double range = (min + (source.getLevel().getScaled(4) * 2)) / multiplier;
if (source instanceof Pony && range > 2) {
range = Math.sqrt(range);

View file

@ -1,9 +1,9 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.Living;
@ -17,31 +17,23 @@ import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSpell, ProjectileDelegate.EntityHitListener {
static final SpellAttribute<Boolean> TARGET_FOCUSED_ENTITY = SpellAttribute.createConditional(SpellAttributes.FOCUSED_ENTITY, Trait.ORDER, order -> order >= 20);
static final SpellAttribute<Boolean> STICK_TO_TARGET = SpellAttribute.createConditional(SpellAttributes.STICK_TO_TARGET, Trait.CHAOS, chaos -> chaos > 0);
static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip);
static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON);
private final EntityReference<Entity> target = new EntityReference<>();
private final Timer timer;
public static void appendTooltip2(CustomisedSpellType<AttractiveSpell> type, List<Text> tooltip) {
TimedSpell.appendDurationTooltip(type, tooltip);
AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip);
if (type.traits().get(Trait.ORDER) >= 20) {
tooltip.add(SpellAttributes.TARGET_ENTITY);
} else {
appendValidTargetsTooltip(type, tooltip);
}
appendCastLocationTooltip(type, tooltip);
}
protected AttractiveSpell(CustomisedSpellType<?> type) {
super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits()));
timer = new Timer(TIME.get(getTraits()));
dataTracker.startTracking(target);
}
@ -52,13 +44,11 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override
public boolean tick(Caster<?> caster, Situation situation) {
if (getType() != SpellType.DARK_VORTEX) {
timer.tick();
if (timer.getTicksRemaining() <= 0) {
return false;
}
}
target.getOrEmpty(caster.asWorld())
.filter(entity -> entity.distanceTo(caster.asEntity()) > getDrawDropOffRange(caster))
@ -87,10 +77,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override
protected boolean isValidTarget(Caster<?> source, Entity entity) {
if (target.referenceEquals(entity)) {
return true;
}
return super.isValidTarget(source, entity);
return target.referenceEquals(entity) || super.isValidTarget(source, entity);
}
@Override
@ -140,7 +127,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override
public boolean setTarget(Entity target) {
if (getTraits().get(Trait.ORDER) >= 20) {
if (TARGET_FOCUSED_ENTITY.get(getTraits())) {
this.target.set(target);
target.setGlowing(true);
return true;
@ -156,7 +143,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override
public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!isDead() && getTraits().get(Trait.CHAOS) > 0) {
if (!isDead() && STICK_TO_TARGET.get(getTraits())) {
setDead();
Caster.of(hit.getEntity()).ifPresent(caster -> getTypeAndTraits().apply(caster, CastingMethod.INDIRECT));
}

View file

@ -1,12 +1,14 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.*;
@ -25,7 +27,6 @@ import net.minecraft.entity.attribute.*;
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
@ -50,10 +51,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
.with(Trait.POWER, 1)
.build();
static void appendTooltip(CustomisedSpellType<? extends BubbleSpell> type, List<Text> tooltip) {
TimedSpell.appendDurationTooltip(type, tooltip);
tooltip.add(SpellAttributes.of(SpellAttributes.SOAPINESS, (int)(type.traits().get(Trait.POWER) * 2)));
}
private static final SpellAttribute<Integer> SOAPINESS = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.REGULAR, Trait.POWER, power -> (int)(power * 2));
static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS);
private final Timer timer;
@ -63,9 +63,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
protected BubbleSpell(CustomisedSpellType<?> type) {
super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits()));
timer = new Timer(TIME.get(getTraits()));
radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
struggles = dataTracker.startTracking(TrackableDataType.INT, (int)(getTraits().get(Trait.POWER) * 2));
struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits()));
}
@Override

View file

@ -1,9 +1,10 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
@ -13,7 +14,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegate.HitListener {
@ -21,9 +21,9 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat
.with(Trait.POWER, 1)
.build();
static void appendTooltip(CustomisedSpellType<? extends DispellEvilSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, (1 + type.relativeTraits().get(Trait.POWER)) * 10));
}
private static final SpellAttribute<Double> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.TIME, AttributeFormat.PERCENTAGE, Trait.POWER, power -> (1 + power) * 10D);
static final TooltipFactory TOOLTIP = RANGE;
protected DispellEvilSpell(CustomisedSpellType<?> type) {
super(type);
@ -35,7 +35,7 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat
return !isDead();
}
source.findAllEntitiesInRange((1 + getTraits().get(Trait.POWER)) * 10, e -> e.getType() == EntityType.PHANTOM).forEach(entity -> {
source.findAllEntitiesInRange(RANGE.get(getTraits()), e -> e.getType() == EntityType.PHANTOM).forEach(entity -> {
entity.damage(entity.getDamageSources().magic(), 50);
if (entity instanceof LivingEntity l) {
double d = source.getOriginVector().getX() - entity.getX();

View file

@ -1,28 +1,27 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.text.Text;
import net.minecraft.util.math.Vec3d;
/**
* An area-effect spell that disperses illusions.
*/
public class DisperseIllusionSpell extends AbstractAreaEffectSpell {
public static void appendTooltip(CustomisedSpellType<? extends DisperseIllusionSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 15 + type.traits().get(Trait.POWER)));
tooltip.add(SpellAttributes.ofTime(SpellAttributes.DURATION, (1 + (long)type.traits().get(Trait.STRENGTH)) * 100));
}
private static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 15 + power));
private static final SpellAttribute<Long> DURATION = SpellAttribute.create(SpellAttributes.DURATION, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> (1 + (long)strength) * 100);
static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, DURATION);
protected DisperseIllusionSpell(CustomisedSpellType<?> type) {
super(type);
@ -31,7 +30,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell {
@Override
public boolean tick(Caster<?> source, Situation situation) {
float range = Math.max(0, 15 + getAdditionalRange());
float range = RANGE.get(getTraits());
if (range == 0) {
return false;
@ -50,7 +49,7 @@ public class DisperseIllusionSpell extends AbstractAreaEffectSpell {
e.getSpellSlot().get(SpellPredicate.CAN_SUPPRESS)
.filter(spell -> spell.isVulnerable(source, this))
.ifPresent(spell -> {
spell.onSuppressed(source, 100 * (1 + getTraits().get(Trait.STRENGTH)));
spell.onSuppressed(source, DURATION.get(getTraits()));
e.playSound(USounds.SPELL_ILLUSION_DISPERSE, 0.2F, 0.5F);
});
});

View file

@ -1,10 +1,11 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
@ -13,18 +14,14 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Vec3d;
public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener {
static void appendTooltip(CustomisedSpellType<? extends DisplacementSpell> type, List<Text> tooltip) {
float damage = type.traits().get(Trait.BLOOD);
if (damage > 0) {
tooltip.add(SpellAttributes.ofRelative(SpellAttributes.DAMAGE_TO_TARGET, damage));
}
}
private static final SpellAttribute<Float> DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributes.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood);
static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET;
private final EntityReference<Entity> target = new EntityReference<>();
@ -81,7 +78,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
entity.setGlowing(false);
entity.playSound(USounds.SPELL_DISPLACEMENT_TELEPORT, 1, 1);
float damage = getTraits().get(Trait.BLOOD);
float damage = DAMAGE_TO_TARGET.get(getTraits());
if (damage > 0) {
entity.damage(source.damageOf(UDamageTypes.EXHAUSTION, source), damage);
}

View file

@ -1,12 +1,13 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference;
@ -17,8 +18,8 @@ import net.minecraft.entity.Entity;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper;
public class FireBoltSpell extends AbstractSpell implements HomingSpell,
ProjectileDelegate.ConfigurationListener, ProjectileDelegate.EntityHitListener {
@ -35,18 +36,14 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
.with(Trait.FIRE, 60)
.build();
public static void appendTooltip(CustomisedSpellType<? extends FireBoltSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.EXPLOSION_STRENGTH, type.traits().get(Trait.POWER, 0, type.traits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F));
tooltip.add(SpellAttributes.of(SpellAttributes.VELOCITY, 1.3F + type.traits().get(Trait.STRENGTH) / 11F));
tooltip.add(SpellAttributes.of(SpellAttributes.PROJECTILE_COUNT, 1 + (int)type.traits().get(Trait.EARTH) * 3));
private static final SpellAttribute<Float> VELOCITY = SpellAttribute.create(SpellAttributes.VELOCITY, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.STRENGTH, strength -> 1.3F + (strength / 11F));
private static final SpellAttribute<Integer> PROJECTILE_COUNT = SpellAttribute.create(SpellAttributes.PROJECTILE_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.EARTH, earth -> 11 + (int)earth * 3);
private static final SpellAttribute<Boolean> FOLLOWS_TARGET = SpellAttribute.createConditional(SpellAttributes.FOLLOWS_TARGET, Trait.FOCUS, focus -> focus >= 50);
private static final SpellAttribute<Float> FOLLOW_RANGE = SpellAttribute.create(SpellAttributes.FOLLOW_RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> Math.max(0F, focus - 49));
private static final SpellAttribute<Float> MAX_EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.FOCUS, focus -> focus >= 50 ? 10F : 1F);
private static final SpellAttribute<Float> EXPLOSION_STRENGTH = SpellAttribute.create(SpellAttributes.EXPLOSION_STRENGTH, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, (traits, focus) -> MathHelper.clamp(focus / 50, 0, MAX_EXPLOSION_STRENGTH.get(traits)));
float homingRange = type.traits().get(Trait.FOCUS);
if (homingRange >= 50) {
tooltip.add(SpellAttributes.FOLLOWS_TARGET);
tooltip.add(SpellAttributes.of(SpellAttributes.FOLLOW_RANGE, homingRange - 50));
}
}
static final TooltipFactory TOOLTIP = TooltipFactory.of(MAX_EXPLOSION_STRENGTH, EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get));
private final EntityReference<Entity> target = new EntityReference<>();
@ -61,10 +58,12 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
@Override
public boolean tick(Caster<?> caster, Situation situation) {
boolean followTarget = FOLLOWS_TARGET.get(getTraits());
float followRage = FOLLOW_RANGE.get(getTraits());
if (situation == Situation.PROJECTILE) {
if (caster instanceof MagicProjectileEntity projectile && getTraits().get(Trait.FOCUS) >= 50) {
if (caster instanceof MagicProjectileEntity projectile && followTarget) {
caster.findAllEntitiesInRange(
getTraits().get(Trait.FOCUS) - 49,
followRage,
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster))
).findFirst().ifPresent(target -> projectile.setHomingTarget(target));
}
@ -72,9 +71,9 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
return true;
}
if (getTraits().get(Trait.FOCUS) >= 50 && target.getOrEmpty(caster.asWorld()).isEmpty()) {
if (followTarget && target.getOrEmpty(caster.asWorld()).isEmpty()) {
target.set(caster.findAllEntitiesInRange(
getTraits().get(Trait.FOCUS) - 49,
followRage,
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster))
).findFirst().orElse(null));
}
@ -92,18 +91,18 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
@Override
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
projectile.setItem(Items.FIRE_CHARGE.getDefaultStack());
projectile.addThrowDamage(getTraits().get(Trait.POWER, 0, getTraits().get(Trait.FOCUS) >= 50 ? 500 : 50) / 10F);
projectile.addThrowDamage(EXPLOSION_STRENGTH.get(getTraits()));
projectile.setFireTicks(900000);
projectile.setVelocity(projectile.getVelocity().multiply(1.3 + getTraits().get(Trait.STRENGTH) / 11F));
projectile.setVelocity(projectile.getVelocity().multiply(VELOCITY.get(getTraits())));
}
protected int getNumberOfBalls(Caster<?> caster) {
return 1 + caster.asWorld().random.nextInt(3) + (int)getTraits().get(Trait.EARTH) * 3;
return PROJECTILE_COUNT.get(getTraits()) + caster.asWorld().random.nextInt(3);
}
@Override
public boolean setTarget(Entity target) {
if (getTraits().get(Trait.FOCUS) >= 50) {
if (FOLLOWS_TARGET.get(getTraits())) {
this.target.set(target);
return true;
}

View file

@ -1,12 +1,9 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
@ -28,7 +25,6 @@ import net.minecraft.entity.damage.DamageTypes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
import net.minecraft.text.Text;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
@ -45,10 +41,6 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
.with(Trait.FIRE, 15)
.build();
public static void appendTooltip(CustomisedSpellType<? extends FireSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER)));
}
protected FireSpell(CustomisedSpellType<?> type) {
super(type);
}
@ -75,14 +67,14 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
generateParticles(source);
}
return new Sphere(false, Math.max(0, 4 + getAdditionalRange())).translate(source.getOrigin()).getBlockPositions().reduce(false,
return new Sphere(false, RANGE.get(getTraits())).translate(source.getOrigin()).getBlockPositions().reduce(false,
(r, i) -> source.canModifyAt(i) && applyBlocks(source.asWorld(), i),
(a, b) -> a || b)
|| applyEntities(source, source.getOriginVector());
}
protected void generateParticles(Caster<?> source) {
source.spawnParticles(new Sphere(false, Math.max(0, 4 + getAdditionalRange())), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> {
source.spawnParticles(new Sphere(false, RANGE.get(getTraits())), (int)(1 + source.getLevel().getScaled(8)) * 6, pos -> {
source.addParticle(ParticleTypes.LARGE_SMOKE, pos, Vec3d.ZERO);
});
}
@ -129,8 +121,12 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
return false;
}
protected float getEntityEffectRange() {
return Math.max(0, RANGE.get(getTraits()) - 1);
}
protected boolean applyEntities(Caster<?> source, Vec3d pos) {
return source.findAllEntitiesInRange(Math.max(0, 3 + getAdditionalRange()), e -> {
return source.findAllEntitiesInRange(getEntityEffectRange(), e -> {
LivingEntity master = source.getMaster();
return (!(e.equals(source.asEntity()) || e.equals(master)) ||
(master instanceof PlayerEntity && !EquinePredicates.PLAYER_UNICORN.test(master))) && !(e instanceof ItemEntity)

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.minelittlepony.unicopia.USounds;
@ -9,7 +8,8 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.advancement.UCriteria;
@ -24,7 +24,6 @@ import net.minecraft.block.*;
import net.minecraft.fluid.*;
import net.minecraft.nbt.*;
import net.minecraft.state.property.Properties;
import net.minecraft.text.Text;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
@ -37,10 +36,8 @@ public class HydrophobicSpell extends AbstractSpell {
.with(Trait.FOCUS, 5)
.with(Trait.KNOWLEDGE, 1)
.build();
static void appendTooltip(CustomisedSpellType<? extends HydrophobicSpell> type, List<Text> tooltip) {
ShieldSpell.appendCastLocationTooltip(type, tooltip);
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER)));
}
static final TooltipFactory TOOLTIP = TooltipFactory.of(ShieldSpell.CAST_ON, ShieldSpell.RANGE);
private final TagKey<Fluid> affectedFluid;
@ -53,7 +50,7 @@ public class HydrophobicSpell extends AbstractSpell {
@Override
public Spell prepareForCast(Caster<?> caster, CastingMethod method) {
if ((method == CastingMethod.DIRECT || method == CastingMethod.STAFF) && getTraits().get(Trait.GENEROSITY) > 0) {
if ((method == CastingMethod.DIRECT || method == CastingMethod.STAFF) && ShieldSpell.CAST_ON.get(getTraits()) == CastOn.LOCATION) {
return toPlaceable();
}
return this;
@ -148,7 +145,7 @@ public class HydrophobicSpell extends AbstractSpell {
*/
public double getRange(Caster<?> source) {
float multiplier = 1;
float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER);
float min = (source instanceof Pony ? 0 : 2) + ShieldSpell.RANGE.get(getTraits());
boolean isLimitedRange = source instanceof Pony || source instanceof MagicProjectileEntity;
double range = (min + (source.getLevel().getScaled(isLimitedRange ? 4 : 40) * (isLimitedRange ? 2 : 10))) / multiplier;
return range;

View file

@ -5,6 +5,10 @@ import java.util.List;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.state.StateMaps;
@ -12,7 +16,6 @@ import com.minelittlepony.unicopia.block.state.StatePredicate;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper;
import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.block.*;
@ -33,8 +36,9 @@ public class IceSpell extends AbstractSpell {
.with(Trait.ICE, 15)
.build();
private static final int RADIUS = 3;
private static final Shape OUTER_RANGE = new Sphere(false, RADIUS);
private static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 3 + power));
static final TooltipFactory TOOLTIP = RANGE;
protected IceSpell(CustomisedSpellType<?> type) {
super(type);
@ -43,11 +47,12 @@ public class IceSpell extends AbstractSpell {
@Override
public boolean tick(Caster<?> source, Situation situation) {
boolean submerged = source.asEntity().isSubmergedInWater() || source.asEntity().isSubmergedIn(FluidTags.LAVA);
float radius = RANGE.get(getTraits());
long blocksAffected = OUTER_RANGE.translate(source.getOrigin()).getBlockPositions().filter(i -> {
long blocksAffected = new Sphere(false, radius).translate(source.getOrigin()).getBlockPositions().filter(i -> {
if (source.canModifyAt(i) && applyBlockSingle(source.asEntity(), source.asWorld(), i, situation)) {
if (submerged & source.getOrigin().isWithinDistance(i, RADIUS - 1)) {
if (submerged & source.getOrigin().isWithinDistance(i, RANGE.get(getTraits()) - 1)) {
BlockState state = source.asWorld().getBlockState(i);
if (state.isIn(BlockTags.ICE) || state.isOf(Blocks.OBSIDIAN)) {
source.asWorld().setBlockState(i, Blocks.AIR.getDefaultState(), Block.NOTIFY_NEIGHBORS);

View file

@ -8,6 +8,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference;
@ -21,7 +24,7 @@ import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileDelegate.HitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
@ -31,10 +34,9 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
.with(Trait.ORDER, 25)
.build();
public static void appendTooltip(CustomisedSpellType<? extends LightSpell> type, List<Text> tooltip) {
TimedSpell.appendDurationTooltip(type, tooltip);
tooltip.add(SpellAttributes.of(SpellAttributes.ORB_COUNT, 2 + (int)(type.relativeTraits().get(Trait.LIFE, 10, 20) / 10F)));
}
private static final SpellAttribute<Integer> ORB_COUNT = SpellAttribute.create(SpellAttributes.ORB_COUNT, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.LIFE, life -> 2 + (int)(MathHelper.clamp(life, 10, 20) / 10F));
static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT);
private final Timer timer;
@ -42,7 +44,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
protected LightSpell(CustomisedSpellType<?> type) {
super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits()));
timer = new Timer(TIME.get(getTraits()));
}
@Override
@ -65,7 +67,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
if (!caster.isClient()) {
if (lights.isEmpty()) {
int size = 2 + caster.asWorld().random.nextInt(2) + (int)(getTraits().get(Trait.LIFE, 10, 20) - 10)/10;
int size = caster.asWorld().random.nextInt(2) + ORB_COUNT.get(getTraits());
while (lights.size() < size) {
lights.add(new EntityReference<>());
}

View file

@ -1,25 +1,21 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, TimedSpell {
static final int BASE_DURATION = 120 * 20;
public static void appendTooltip(CustomisedSpellType<? extends MimicSpell> type, List<Text> tooltip) {
TimedSpell.appendDurationTooltip(type, tooltip);
}
static final TooltipFactory TOOLTIP = TimedSpell.TIME;
private final Timer timer;
protected MimicSpell(CustomisedSpellType<?> type) {
super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits()));
timer = new Timer(TIME.get(getTraits()));
}
@Override

View file

@ -9,6 +9,9 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.EntityReference;
@ -32,7 +35,6 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos;
@ -81,10 +83,8 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
return e -> e.getType() == type;
}
static void appendTooltip(CustomisedSpellType<? extends NecromancySpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER)));
tooltip.add(SpellAttributes.of(SpellAttributes.WAVE_SIZE, 10 + (int)type.traits().get(Trait.CHAOS, 0, 10)));
}
static final SpellAttribute<Integer> WAVE_SIZE = SpellAttribute.create(SpellAttributes.WAVE_SIZE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.CHAOS, chaos -> 10 + (int)MathHelper.clamp(chaos, 0, 10));
static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, WAVE_SIZE);
private final List<EntityReference<LivingEntity>> summonedEntities = new ArrayList<>();
@ -97,7 +97,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
@Override
public boolean tick(Caster<?> source, Situation situation) {
float radius = 4 + source.getLevel().getScaled(4) * 4 + getAdditionalRange();
float radius = source.getLevel().getScaled(4) * 4 + RANGE.get(getTraits());
if (radius <= 0) {
return false;
@ -129,14 +129,16 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
return true;
}).isEmpty());
float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + getTraits().get(Trait.CHAOS, 0, 10);
if (--spawnCountdown > 0 && !summonedEntities.isEmpty()) {
return true;
}
// TODO: refactory speed attribute
// TODO: weather resistant attribute
spawnCountdown = 1200 + source.asWorld().random.nextInt(rainy ? 2000 : 1000);
if (summonedEntities.size() > 10 + additional) {
float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + WAVE_SIZE.get(getTraits());
if (summonedEntities.size() > additional) {
return true;
}

View file

@ -36,7 +36,7 @@ public class ScorchSpell extends FireSpell implements ProjectileDelegate.Configu
BlockPos pos = PosHelper.findSolidGroundAt(source.asWorld(), source.getOrigin(), source.getPhysics().getGravitySignum());
if (source.canModifyAt(pos) && StateMaps.FIRE_AFFECTED.convert(source.asWorld(), pos)) {
source.spawnParticles(new Sphere(false, Math.max(1, getAdditionalRange())), 5, p -> {
source.spawnParticles(new Sphere(false, RANGE.get(getTraits())), 5, p -> {
source.addParticle(ParticleTypes.SMOKE, PosHelper.offset(p, pos), Vec3d.ZERO);
});
}

View file

@ -1,17 +1,19 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import java.util.Optional;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.AttributeFormat;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.CastOn;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.SpellAttribute;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
@ -38,7 +40,6 @@ import net.minecraft.entity.passive.PassiveEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
@ -50,31 +51,18 @@ public class ShieldSpell extends AbstractSpell {
.with(Trait.AIR, 9)
.build();
static void appendTooltip(CustomisedSpellType<? extends ShieldSpell> type, List<Text> tooltip) {
AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip);
appendValidTargetsTooltip(type, tooltip);
appendCastLocationTooltip(type, tooltip);
}
static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power));
protected static final SpellAttribute<CastOn> CAST_ON = SpellAttribute.createEnumerated(SpellAttributes.CAST_ON, Trait.GENEROSITY, generosity -> generosity > 0 ? CastOn.LOCATION : CastOn.SELF);
static void appendValidTargetsTooltip(CustomisedSpellType<? extends ShieldSpell> type, List<Text> tooltip) {
if (type.traits().get(Trait.KNOWLEDGE) > 10) {
tooltip.add(SpellAttributes.PERMIT_ITEMS);
} else {
if (type.traits().get(Trait.LIFE) > 0) {
tooltip.add(SpellAttributes.PERMIT_PASSIVE);
}
if (type.traits().get(Trait.BLOOD) > 0) {
tooltip.add(SpellAttributes.PERMIT_HOSTILE);
}
if (type.traits().get(Trait.ICE) > 0) {
tooltip.add(SpellAttributes.PERMIT_PLAYER);
}
}
}
static final SpellAttribute<Boolean> TARGET_ITEMS = SpellAttribute.createConditional(SpellAttributes.PERMIT_ITEMS, Trait.KNOWLEDGE, knowledge -> knowledge > 10);
static final SpellAttribute<Boolean> PERMIT_PASSIVE = SpellAttribute.createConditional(SpellAttributes.PERMIT_PASSIVE, Trait.LIFE, l -> l > 0);
static final SpellAttribute<Boolean> PERMIT_HOSTILE = SpellAttribute.createConditional(SpellAttributes.PERMIT_HOSTILE, Trait.BLOOD, l -> l > 0);
static final SpellAttribute<Boolean> PERMIT_PLAYER = SpellAttribute.createConditional(SpellAttributes.PERMIT_PLAYER, Trait.ICE, l -> l > 0);
static void appendCastLocationTooltip(CustomisedSpellType<?> type, List<Text> tooltip) {
tooltip.add(type.traits().get(Trait.GENEROSITY) > 0 ? SpellAttributes.CAST_ON_LOCATION : SpellAttributes.CAST_ON_PERSON);
}
static final TooltipFactory PERMIT_ENTITY = TooltipFactory.of(PERMIT_PASSIVE, PERMIT_HOSTILE, PERMIT_PLAYER);
static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_ITEMS.get(type.traits()) ? TARGET_ITEMS : PERMIT_ENTITY).appendTooltip(type, tooltip);
static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, TARGET, CAST_ON);
protected final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget);
@ -90,7 +78,7 @@ public class ShieldSpell extends AbstractSpell {
@Override
public Spell prepareForCast(Caster<?> caster, CastingMethod method) {
return method == CastingMethod.STAFF || getTraits().get(Trait.GENEROSITY) > 0 ? toPlaceable() : this;
return method == CastingMethod.STAFF || CAST_ON.get(getTraits()) == CastOn.LOCATION ? toPlaceable() : this;
}
@Override
@ -176,7 +164,7 @@ public class ShieldSpell extends AbstractSpell {
* Calculates the maximum radius of the shield. aka The area of effect.
*/
public double getDrawDropOffRange(Caster<?> source) {
float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER);
float min = (source instanceof Pony ? 0 : 2) + RANGE.get(getTraits());
double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / rangeMultiplier.getValue();
return range;
@ -184,7 +172,7 @@ public class ShieldSpell extends AbstractSpell {
protected boolean isValidTarget(Caster<?> source, Entity entity) {
if (getTraits().get(Trait.KNOWLEDGE) > 10) {
if (TARGET_ITEMS.get(getTraits())) {
return entity instanceof ItemEntity;
}
@ -198,13 +186,13 @@ public class ShieldSpell extends AbstractSpell {
|| entity instanceof BoatEntity
);
if (getTraits().get(Trait.LIFE) > 0) {
if (PERMIT_PASSIVE.get(getTraits())) {
valid &= !(entity instanceof PassiveEntity);
}
if (getTraits().get(Trait.BLOOD) > 0) {
if (PERMIT_HOSTILE.get(getTraits())) {
valid &= !(entity instanceof HostileEntity);
}
if (getTraits().get(Trait.ICE) > 0) {
if (PERMIT_PLAYER.get(getTraits())) {
valid &= !(entity instanceof PlayerEntity);
}
return valid;

View file

@ -12,7 +12,6 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.Pony;
@ -31,7 +30,6 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
@ -41,10 +39,6 @@ import net.minecraft.util.math.Vec3d;
public class SiphoningSpell extends AbstractAreaEffectSpell {
static final Predicate<Entity> TARGET_PREDICATE = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_LIVING_ENTITY);
static void appendTooltip(CustomisedSpellType<? extends SiphoningSpell> type, List<Text> tooltip) {
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4));
}
private final DataTracker.Entry<Boolean> upset = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private int ticksUpset;
@ -65,7 +59,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell {
}
if (source.isClient()) {
float radius = 4 + source.getLevel().getScaled(5) + getAdditionalRange();
float radius = source.getLevel().getScaled(5) + RANGE.get(getTraits());
int direction = isFriendlyTogether(source) ? 1 : -1;
source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> {

View file

@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
@ -17,6 +18,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.UItems;
@ -53,31 +55,31 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
public static final SpellType<RageAbilitySpell> RAGE = register("rage", builder(RageAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.FLAME));
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", builder(TimeControlAbilitySpell::new).color(0xBDBDF9).unobtainable().shape(GemstoneItem.Shape.STAR));
public static final SpellType<IceSpell> FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS));
public static final SpellType<IceSpell> FROST = register("frost", builder(IceSpell::new).color(0xEABBFF).shape(GemstoneItem.Shape.TRIANGLE).traits(IceSpell.DEFAULT_TRAITS).tooltip(IceSpell.TOOLTIP));
public static final SpellType<ChillingBreathSpell> CHILLING_BREATH = register("chilling_breath", builder(ChillingBreathSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEAFF).shape(GemstoneItem.Shape.TRIANGLE).traits(ChillingBreathSpell.DEFAULT_TRAITS));
public static final SpellType<ScorchSpell> SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip));
public static final SpellType<FireSpell> FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip));
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS).tooltip(FireSpell::appendTooltip));
public static final SpellType<ShieldSpell> SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell::appendTooltip));
public static final SpellType<AreaProtectionSpell> ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS).tooltip(AreaProtectionSpell::appendTooltip));
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS).tooltip(AttractiveSpell::appendTooltip2));
public static final SpellType<ScorchSpell> SCORCH = register("scorch", builder(ScorchSpell::new).affinity(Affinity.BAD).color(0xF8EC1F).stackable().shape(GemstoneItem.Shape.FLAME).traits(ScorchSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP));
public static final SpellType<FireSpell> FLAME = register("flame", builder(FireSpell::new).color(0xFFBB99).shape(GemstoneItem.Shape.FLAME).traits(FireSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP));
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", builder(InfernoSpell::new).affinity(Affinity.BAD).color(0xFFAA00).shape(GemstoneItem.Shape.FLAME).traits(InfernoSpell.DEFAULT_TRAITS).tooltip(AbstractAreaEffectSpell.TOOLTIP));
public static final SpellType<ShieldSpell> SHIELD = register("shield", builder(ShieldSpell::new).affinity(Affinity.NEUTRAL).color(0x66CDAA).shape(GemstoneItem.Shape.SHIELD).traits(ShieldSpell.DEFAULT_TRAITS).tooltip(ShieldSpell.TOOLTIP));
public static final SpellType<AreaProtectionSpell> ARCANE_PROTECTION = register("arcane_protection", builder(AreaProtectionSpell::new).affinity(Affinity.BAD).color(0x99CDAA).shape(GemstoneItem.Shape.SHIELD).traits(AreaProtectionSpell.DEFAULT_TRAITS).tooltip(AreaProtectionSpell.TOOLTIP));
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", builder(AttractiveSpell::new).affinity(Affinity.NEUTRAL).color(0xFFEA88).shape(GemstoneItem.Shape.VORTEX).traits(AttractiveSpell.DEFAULT_TRAITS).tooltip(AttractiveSpell.TOOLTIP));
public static final SpellType<DarkVortexSpell> DARK_VORTEX = register("dark_vortex", builder(DarkVortexSpell::new).affinity(Affinity.BAD).color(0xA33333).stackable().shape(GemstoneItem.Shape.VORTEX).traits(DarkVortexSpell.DEFAULT_TRAITS));
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL).tooltip(NecromancySpell::appendTooltip));
public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA).tooltip(SiphoningSpell::appendTooltip));
public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell::appendTooltip));
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", builder(NecromancySpell::new).affinity(Affinity.BAD).color(0xFA3A3A).shape(GemstoneItem.Shape.SKULL).tooltip(NecromancySpell.TOOLTIP));
public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", builder(SiphoningSpell::new).affinity(Affinity.NEUTRAL).color(0xFFA3AA).shape(GemstoneItem.Shape.LAMBDA).tooltip(AbstractAreaEffectSpell.TOOLTIP));
public static final SpellType<DisperseIllusionSpell> REVEALING = register("reveal", builder(DisperseIllusionSpell::new).color(0xFFFFAF).shape(GemstoneItem.Shape.CROSS).tooltip(DisperseIllusionSpell.TOOLTIP));
public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", builder(AwkwardSpell::new).affinity(Affinity.NEUTRAL).color(0x3A59FF).shape(GemstoneItem.Shape.ICE));
public static final SpellType<TransformationSpell> TRANSFORMATION = register("transformation", builder(TransformationSpell::new).color(0x19E48E).shape(GemstoneItem.Shape.BRUSH));
public static final SpellType<FeatherFallSpell> FEATHER_FALL = register("feather_fall", builder(FeatherFallSpell::new).color(0x00EEFF).shape(GemstoneItem.Shape.LAMBDA).traits(FeatherFallSpell.DEFAULT_TRAITS).tooltip(FeatherFallSpell::appendTooltip));
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP::appendTooltip));
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell::appendTooltip));
public static final SpellType<LightSpell> LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell::appendTooltip));
public static final SpellType<DisplacementSpell> DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell::appendTooltip));
public static final SpellType<CatapultSpell> CATAPULT = register("catapult", builder(CatapultSpell::new).color(0x22FF00).shape(GemstoneItem.Shape.ROCKET).traits(CatapultSpell.DEFAULT_TRAITS).tooltip(CatapultSpell.TOOLTIP));
public static final SpellType<FireBoltSpell> FIRE_BOLT = register("fire_bolt", builder(FireBoltSpell::new).color(0xFF8811).shape(GemstoneItem.Shape.FLAME).traits(FireBoltSpell.DEFAULT_TRAITS).tooltip(FireBoltSpell.TOOLTIP));
public static final SpellType<LightSpell> LIGHT = register("light", builder(LightSpell::new).color(0xEEFFAA).shape(GemstoneItem.Shape.STAR).traits(LightSpell.DEFAULT_TRAITS).tooltip(LightSpell.TOOLTIP));
public static final SpellType<DisplacementSpell> DISPLACEMENT = register("displacement", builder(DisplacementSpell::new).affinity(Affinity.NEUTRAL).color(0x9900FF).stackable().shape(GemstoneItem.Shape.BRUSH).traits(PortalSpell.DEFAULT_TRAITS).tooltip(DisplacementSpell.TOOLTIP));
public static final SpellType<PortalSpell> PORTAL = register("portal", builder(PortalSpell::new).color(0x99FFFF).shape(GemstoneItem.Shape.RING).traits(PortalSpell.DEFAULT_TRAITS));
public static final SpellType<MimicSpell> MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW).tooltip(MimicSpell::appendTooltip));
public static final SpellType<MindSwapSpell> MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE).tooltip(MimicSpell::appendTooltip));
public static final SpellType<HydrophobicSpell> HYDROPHOBIC = register("hydrophobic", SpellType.<HydrophobicSpell>builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET).tooltip(HydrophobicSpell::appendTooltip));
public static final SpellType<BubbleSpell> BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS).tooltip(BubbleSpell::appendTooltip));
public static final SpellType<DispellEvilSpell> DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS).tooltip(DispellEvilSpell::appendTooltip));
public static final SpellType<MimicSpell> MIMIC = register("mimic", builder(MimicSpell::new).color(0xFFFF00).shape(GemstoneItem.Shape.ARROW).tooltip(MimicSpell.TOOLTIP));
public static final SpellType<MindSwapSpell> MIND_SWAP = register("mind_swap", builder(MindSwapSpell::new).affinity(Affinity.BAD).color(0xF9FF99).shape(GemstoneItem.Shape.WAVE).tooltip(MimicSpell.TOOLTIP));
public static final SpellType<HydrophobicSpell> HYDROPHOBIC = register("hydrophobic", SpellType.<HydrophobicSpell>builder(s -> new HydrophobicSpell(s, FluidTags.WATER)).affinity(Affinity.NEUTRAL).color(0xF999FF).stackable().shape(GemstoneItem.Shape.ROCKET).tooltip(HydrophobicSpell.TOOLTIP));
public static final SpellType<BubbleSpell> BUBBLE = register("bubble", builder(BubbleSpell::new).affinity(Affinity.NEUTRAL).color(0xF999FF).shape(GemstoneItem.Shape.DONUT).traits(BubbleSpell.DEFAULT_TRAITS).tooltip(BubbleSpell.TOOLTIP));
public static final SpellType<DispellEvilSpell> DISPEL_EVIL = register("dispel_evil", builder(DispellEvilSpell::new).color(0x00FF00).shape(GemstoneItem.Shape.CROSS).traits(DispellEvilSpell.DEFAULT_TRAITS).tooltip(DispellEvilSpell.TOOLTIP));
public static void bootstrap() {}
@ -274,6 +276,12 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return this;
}
public Builder<T> tooltip(TooltipFactory tooltipFunction) {
this.tooltipFunction = tooltipFunction::appendTooltip;
return this;
}
@Deprecated
public Builder<T> tooltip(BiConsumer<CustomisedSpellType<T>, List<Text>> tooltipFunction) {
this.tooltipFunction = tooltipFunction;
return this;