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; package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.effect.*;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import net.minecraft.text.Text;
public abstract class AbstractAreaEffectSpell extends AbstractSpell { public abstract class AbstractAreaEffectSpell extends AbstractSpell {
protected static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power));
public static void appendRangeTooltip(CustomisedSpellType<?> type, List<Text> tooltip) { public static final TooltipFactory TOOLTIP = RANGE;
float addedRange = type.traits().get(Trait.POWER);
if (addedRange != 0) {
tooltip.add(SpellAttributes.ofRelative(SpellAttributes.RANGE, addedRange));
}
}
protected AbstractAreaEffectSpell(CustomisedSpellType<?> type) { protected AbstractAreaEffectSpell(CustomisedSpellType<?> type) {
super(type); super(type);
@ -24,8 +19,4 @@ public abstract class AbstractAreaEffectSpell extends AbstractSpell {
public Spell prepareForCast(Caster<?> caster, CastingMethod method) { public Spell prepareForCast(Caster<?> caster, CastingMethod method) {
return toPlaceable(); 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 { public interface SpellAttributes {
Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location")); Text CAST_ON_LOCATION = of(Unicopia.id("cast_on_location"));
Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person")); Text CAST_ON_PERSON = of(Unicopia.id("cast_on_person"));
Text TARGET_ENTITY = of(Unicopia.id("focused_entity")); Identifier FOLLOWS_TARGET = Unicopia.id("follows_target");
Text FOLLOWS_TARGET = of(Unicopia.id("follows_target"));
Text PERMIT_ITEMS = of(Unicopia.id("permit_items")); Identifier PERMIT_ITEMS = Unicopia.id("permit_items");
Text PERMIT_PASSIVE = of(Unicopia.id("permit_passive")); Identifier PERMIT_PASSIVE = Unicopia.id("permit_passive");
Text PERMIT_HOSTILE = of(Unicopia.id("permit_hostile")); Identifier PERMIT_HOSTILE = Unicopia.id("permit_hostile");
Text PERMIT_PLAYER = of(Unicopia.id("permit_player")); Identifier PERMIT_PLAYER = Unicopia.id("permit_player");
Identifier FOCUSED_ENTITY = Unicopia.id("focused_entity");
Identifier RANGE = Unicopia.id("range"); Identifier RANGE = Unicopia.id("range");
Identifier DURATION = Unicopia.id("duration"); Identifier DURATION = Unicopia.id("duration");
Identifier STRENGTH = Unicopia.id("strength"); Identifier STRENGTH = Unicopia.id("strength");
@ -38,15 +38,20 @@ public interface SpellAttributes {
Identifier ORB_COUNT = Unicopia.id("orb_count"); Identifier ORB_COUNT = Unicopia.id("orb_count");
Identifier WAVE_SIZE = Unicopia.id("wave_size"); Identifier WAVE_SIZE = Unicopia.id("wave_size");
Identifier FOLLOW_RANGE = Unicopia.id("follow_range"); 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 SOAPINESS = Unicopia.id("soapiness");
Identifier CAST_ON = Unicopia.id("cast_on");
Identifier TARGET_PREFERENCE = Unicopia.id("target_preference"); Identifier TARGET_PREFERENCE = Unicopia.id("target_preference");
Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference"); Identifier CASTER_PREFERENCE = Unicopia.id("caster_preference");
@Deprecated
static Text of(Identifier id) { static Text of(Identifier id) {
return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE); return Text.literal(" ").append(Text.translatable(Util.createTranslationKey("spell_attribute", id))).formatted(Formatting.LIGHT_PURPLE);
} }
@Deprecated
static Text of(Identifier id, float value) { static Text of(Identifier id, float value) {
return Text.literal(" ").append( return Text.literal(" ").append(
Text.translatable("attribute.modifier.equals.0", Text.translatable("attribute.modifier.equals.0",
@ -55,10 +60,12 @@ public interface SpellAttributes {
).formatted(Formatting.LIGHT_PURPLE); ).formatted(Formatting.LIGHT_PURPLE);
} }
@Deprecated
static Text ofRelative(Identifier id, float value) { static Text ofRelative(Identifier id, float value) {
return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false); return EffectUtils.formatModifierChange(Util.createTranslationKey("spell_attribute", id), value, false);
} }
@Deprecated
static Text ofTime(Identifier id, long time) { static Text ofTime(Identifier id, long time) {
return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0", return Text.literal(" ").append(Text.translatable("attribute.modifier.equals.0",
StringHelper.formatTicks((int)Math.abs(time)), StringHelper.formatTicks((int)Math.abs(time)),
@ -66,6 +73,7 @@ public interface SpellAttributes {
).formatted(Formatting.LIGHT_PURPLE)); ).formatted(Formatting.LIGHT_PURPLE));
} }
@Deprecated
public enum ValueType { public enum ValueType {
REGULAR, REGULAR,
TIME, TIME,

View file

@ -1,15 +1,12 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List; 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.effect.CustomisedSpellType;
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.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
/** /**
@ -17,17 +14,10 @@ import net.minecraft.util.math.MathHelper;
*/ */
public interface TimedSpell extends Spell { public interface TimedSpell extends Spell {
int BASE_DURATION = 120 * 20; 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(); 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 { class Timer implements Tickable, NbtSerialisable {
private int maxDuration; private int maxDuration;
private int duration; 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.List;
import java.util.Locale; import java.util.Locale;
import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -18,7 +19,7 @@ import net.minecraft.util.Util;
public record SpellAttribute<T> ( public record SpellAttribute<T> (
Trait trait, Trait trait,
Float2ObjectFunction<T> valueGetter, BiFunction<SpellTraits, Float, T> valueGetter,
TooltipFactory tooltipFactory TooltipFactory tooltipFactory
) implements TooltipFactory { ) implements TooltipFactory {
@Override @Override
@ -27,7 +28,11 @@ public record SpellAttribute<T> (
} }
public T get(SpellTraits traits) { 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) { 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); 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) { 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)); Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id));
return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> { return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> {
float traitAmount = type.traits().get(trait); float traitAmount = type.traits().get(trait);
float traitDifference = type.relativeTraits().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); var b = baseFormat.getBase(name, value, "equals", Formatting.LIGHT_PURPLE);
if (traitDifference != 0) { 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)); tooltip.add(AttributeFormat.formatTraitDifference(trait, traitDifference));
} else { } else {
tooltip.add(b); tooltip.add(b);
@ -56,11 +69,15 @@ public record SpellAttribute<T> (
} }
public static SpellAttribute<Boolean> createConditional(Identifier id, Trait trait, Float2ObjectFunction<Boolean> valueGetter) { 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) -> { return new SpellAttribute<>(trait, valueGetter, (CustomisedSpellType<?> type, List<Text> tooltip) -> {
Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id)); Text name = Text.translatable(Util.createTranslationKey("spell_attribute", id));
float difference = type.relativeTraits().get(trait); float difference = type.relativeTraits().get(trait);
Text value = AttributeFormat.formatAttributeLine(name); 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); value = value.copy().formatted(Formatting.STRIKETHROUGH, Formatting.DARK_GRAY);
} }
tooltip.add(value); 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) { 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))))); 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) -> { 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) { if (t != null) {
int max = t.getClass().getEnumConstants().length; int max = t.getClass().getEnumConstants().length;

View file

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

View file

@ -1,9 +1,9 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; 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.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*; 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.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.Living; 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.entity.Entity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSpell, ProjectileDelegate.EntityHitListener { 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 EntityReference<Entity> target = new EntityReference<>();
private final Timer timer; 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) { protected AttractiveSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); timer = new Timer(TIME.get(getTraits()));
dataTracker.startTracking(target); dataTracker.startTracking(target);
} }
@ -52,13 +44,11 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override @Override
public boolean tick(Caster<?> caster, Situation situation) { public boolean tick(Caster<?> caster, Situation situation) {
if (getType() != SpellType.DARK_VORTEX) {
timer.tick(); timer.tick();
if (timer.getTicksRemaining() <= 0) { if (timer.getTicksRemaining() <= 0) {
return false; return false;
} }
}
target.getOrEmpty(caster.asWorld()) target.getOrEmpty(caster.asWorld())
.filter(entity -> entity.distanceTo(caster.asEntity()) > getDrawDropOffRange(caster)) .filter(entity -> entity.distanceTo(caster.asEntity()) > getDrawDropOffRange(caster))
@ -87,10 +77,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override @Override
protected boolean isValidTarget(Caster<?> source, Entity entity) { protected boolean isValidTarget(Caster<?> source, Entity entity) {
if (target.referenceEquals(entity)) { return target.referenceEquals(entity) || super.isValidTarget(source, entity);
return true;
}
return super.isValidTarget(source, entity);
} }
@Override @Override
@ -140,7 +127,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override @Override
public boolean setTarget(Entity target) { public boolean setTarget(Entity target) {
if (getTraits().get(Trait.ORDER) >= 20) { if (TARGET_FOCUSED_ENTITY.get(getTraits())) {
this.target.set(target); this.target.set(target);
target.setGlowing(true); target.setGlowing(true);
return true; return true;
@ -156,7 +143,7 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
@Override @Override
public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!isDead() && getTraits().get(Trait.CHAOS) > 0) { if (!isDead() && STICK_TO_TARGET.get(getTraits())) {
setDead(); setDead();
Caster.of(hit.getEntity()).ifPresent(caster -> getTypeAndTraits().apply(caster, CastingMethod.INDIRECT)); 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; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*; 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.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.*;
@ -25,7 +27,6 @@ import net.minecraft.entity.attribute.*;
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -50,10 +51,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
.with(Trait.POWER, 1) .with(Trait.POWER, 1)
.build(); .build();
static void appendTooltip(CustomisedSpellType<? extends BubbleSpell> type, List<Text> tooltip) { private static final SpellAttribute<Integer> SOAPINESS = SpellAttribute.create(SpellAttributes.SOAPINESS, AttributeFormat.REGULAR, Trait.POWER, power -> (int)(power * 2));
TimedSpell.appendDurationTooltip(type, tooltip);
tooltip.add(SpellAttributes.of(SpellAttributes.SOAPINESS, (int)(type.traits().get(Trait.POWER) * 2))); static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS);
}
private final Timer timer; private final Timer timer;
@ -63,9 +63,9 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
protected BubbleSpell(CustomisedSpellType<?> type) { protected BubbleSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); timer = new Timer(TIME.get(getTraits()));
radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); 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 @Override

View file

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

View file

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

View file

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

View file

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

View file

@ -1,12 +1,9 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; 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.AbstractAreaEffectSpell;
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;
@ -28,7 +25,6 @@ import net.minecraft.entity.damage.DamageTypes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.text.Text;
import net.minecraft.registry.tag.BlockTags; import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.EntityHitResult;
@ -45,10 +41,6 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
.with(Trait.FIRE, 15) .with(Trait.FIRE, 15)
.build(); .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) { protected FireSpell(CustomisedSpellType<?> type) {
super(type); super(type);
} }
@ -75,14 +67,14 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
generateParticles(source); 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), (r, i) -> source.canModifyAt(i) && applyBlocks(source.asWorld(), i),
(a, b) -> a || b) (a, b) -> a || b)
|| applyEntities(source, source.getOriginVector()); || applyEntities(source, source.getOriginVector());
} }
protected void generateParticles(Caster<?> source) { 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); source.addParticle(ParticleTypes.LARGE_SMOKE, pos, Vec3d.ZERO);
}); });
} }
@ -129,8 +121,12 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDele
return false; return false;
} }
protected float getEntityEffectRange() {
return Math.max(0, RANGE.get(getTraits()) - 1);
}
protected boolean applyEntities(Caster<?> source, Vec3d pos) { 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(); LivingEntity master = source.getMaster();
return (!(e.equals(source.asEntity()) || e.equals(master)) || return (!(e.equals(source.asEntity()) || e.equals(master)) ||
(master instanceof PlayerEntity && !EquinePredicates.PLAYER_UNICORN.test(master))) && !(e instanceof ItemEntity) (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; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import com.minelittlepony.unicopia.USounds; 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.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; 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.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.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
@ -24,7 +24,6 @@ import net.minecraft.block.*;
import net.minecraft.fluid.*; import net.minecraft.fluid.*;
import net.minecraft.nbt.*; import net.minecraft.nbt.*;
import net.minecraft.state.property.Properties; import net.minecraft.state.property.Properties;
import net.minecraft.text.Text;
import net.minecraft.registry.tag.TagKey; import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -37,10 +36,8 @@ public class HydrophobicSpell extends AbstractSpell {
.with(Trait.FOCUS, 5) .with(Trait.FOCUS, 5)
.with(Trait.KNOWLEDGE, 1) .with(Trait.KNOWLEDGE, 1)
.build(); .build();
static void appendTooltip(CustomisedSpellType<? extends HydrophobicSpell> type, List<Text> tooltip) {
ShieldSpell.appendCastLocationTooltip(type, tooltip); static final TooltipFactory TOOLTIP = TooltipFactory.of(ShieldSpell.CAST_ON, ShieldSpell.RANGE);
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER)));
}
private final TagKey<Fluid> affectedFluid; private final TagKey<Fluid> affectedFluid;
@ -53,7 +50,7 @@ public class HydrophobicSpell extends AbstractSpell {
@Override @Override
public Spell prepareForCast(Caster<?> caster, CastingMethod method) { 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 toPlaceable();
} }
return this; return this;
@ -148,7 +145,7 @@ public class HydrophobicSpell extends AbstractSpell {
*/ */
public double getRange(Caster<?> source) { public double getRange(Caster<?> source) {
float multiplier = 1; 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; boolean isLimitedRange = source instanceof Pony || source instanceof MagicProjectileEntity;
double range = (min + (source.getLevel().getScaled(isLimitedRange ? 4 : 40) * (isLimitedRange ? 2 : 10))) / multiplier; double range = (min + (source.getLevel().getScaled(isLimitedRange ? 4 : 40) * (isLimitedRange ? 2 : 10))) / multiplier;
return range; return range;

View file

@ -5,6 +5,10 @@ import java.util.List;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; 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.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.state.StateMaps; 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.particle.ParticleUtils;
import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper; import com.minelittlepony.unicopia.util.VecHelper;
import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.block.*; import net.minecraft.block.*;
@ -33,8 +36,9 @@ public class IceSpell extends AbstractSpell {
.with(Trait.ICE, 15) .with(Trait.ICE, 15)
.build(); .build();
private static final int RADIUS = 3; private static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 3 + power));
private static final Shape OUTER_RANGE = new Sphere(false, RADIUS);
static final TooltipFactory TOOLTIP = RANGE;
protected IceSpell(CustomisedSpellType<?> type) { protected IceSpell(CustomisedSpellType<?> type) {
super(type); super(type);
@ -43,11 +47,12 @@ public class IceSpell extends AbstractSpell {
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
boolean submerged = source.asEntity().isSubmergedInWater() || source.asEntity().isSubmergedIn(FluidTags.LAVA); 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 (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); BlockState state = source.asWorld().getBlockState(i);
if (state.isIn(BlockTags.ICE) || state.isOf(Blocks.OBSIDIAN)) { if (state.isIn(BlockTags.ICE) || state.isOf(Blocks.OBSIDIAN)) {
source.asWorld().setBlockState(i, Blocks.AIR.getDefaultState(), Block.NOTIFY_NEIGHBORS); 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.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes;
import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; 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.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference; 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.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList; 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 class LightSpell extends AbstractSpell implements TimedSpell, ProjectileDelegate.HitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() 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) .with(Trait.ORDER, 25)
.build(); .build();
public static void appendTooltip(CustomisedSpellType<? extends LightSpell> type, List<Text> tooltip) { 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));
TimedSpell.appendDurationTooltip(type, tooltip);
tooltip.add(SpellAttributes.of(SpellAttributes.ORB_COUNT, 2 + (int)(type.relativeTraits().get(Trait.LIFE, 10, 20) / 10F))); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT);
}
private final Timer timer; private final Timer timer;
@ -42,7 +44,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
protected LightSpell(CustomisedSpellType<?> type) { protected LightSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); timer = new Timer(TIME.get(getTraits()));
} }
@Override @Override
@ -65,7 +67,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
if (!caster.isClient()) { if (!caster.isClient()) {
if (lights.isEmpty()) { 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) { while (lights.size() < size) {
lights.add(new EntityReference<>()); lights.add(new EntityReference<>());
} }

View file

@ -1,25 +1,21 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; 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.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text;
public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, TimedSpell { 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) { static final TooltipFactory TOOLTIP = TimedSpell.TIME;
TimedSpell.appendDurationTooltip(type, tooltip);
}
private final Timer timer; private final Timer timer;
protected MimicSpell(CustomisedSpellType<?> type) { protected MimicSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(BASE_DURATION + TimedSpell.getExtraDuration(getTraits())); timer = new Timer(TIME.get(getTraits()));
} }
@Override @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.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.SpellAttributes; 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.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
@ -32,7 +35,6 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList; import net.minecraft.nbt.NbtList;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.text.Text;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -81,10 +83,8 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
return e -> e.getType() == type; return e -> e.getType() == type;
} }
static void appendTooltip(CustomisedSpellType<? extends NecromancySpell> type, List<Text> tooltip) { 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));
tooltip.add(SpellAttributes.of(SpellAttributes.RANGE, 4 + type.traits().get(Trait.POWER))); static final TooltipFactory TOOLTIP = TooltipFactory.of(RANGE, WAVE_SIZE);
tooltip.add(SpellAttributes.of(SpellAttributes.WAVE_SIZE, 10 + (int)type.traits().get(Trait.CHAOS, 0, 10)));
}
private final List<EntityReference<LivingEntity>> summonedEntities = new ArrayList<>(); private final List<EntityReference<LivingEntity>> summonedEntities = new ArrayList<>();
@ -97,7 +97,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { 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) { if (radius <= 0) {
return false; return false;
@ -129,14 +129,16 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
return true; return true;
}).isEmpty()); }).isEmpty());
float additional = source.asWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty() + getTraits().get(Trait.CHAOS, 0, 10);
if (--spawnCountdown > 0 && !summonedEntities.isEmpty()) { if (--spawnCountdown > 0 && !summonedEntities.isEmpty()) {
return true; return true;
} }
// TODO: refactory speed attribute
// TODO: weather resistant attribute
spawnCountdown = 1200 + source.asWorld().random.nextInt(rainy ? 2000 : 1000); 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; 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()); BlockPos pos = PosHelper.findSolidGroundAt(source.asWorld(), source.getOrigin(), source.getPhysics().getGravitySignum());
if (source.canModifyAt(pos) && StateMaps.FIRE_AFFECTED.convert(source.asWorld(), pos)) { 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); source.addParticle(ParticleTypes.SMOKE, PosHelper.offset(p, pos), Vec3d.ZERO);
}); });
} }

View file

@ -1,17 +1,19 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; 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.SpellAttributes; 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.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; 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.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.BoatEntity; import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -50,31 +51,18 @@ public class ShieldSpell extends AbstractSpell {
.with(Trait.AIR, 9) .with(Trait.AIR, 9)
.build(); .build();
static void appendTooltip(CustomisedSpellType<? extends ShieldSpell> type, List<Text> tooltip) { static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributes.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power));
AbstractAreaEffectSpell.appendRangeTooltip(type, tooltip); protected static final SpellAttribute<CastOn> CAST_ON = SpellAttribute.createEnumerated(SpellAttributes.CAST_ON, Trait.GENEROSITY, generosity -> generosity > 0 ? CastOn.LOCATION : CastOn.SELF);
appendValidTargetsTooltip(type, tooltip);
appendCastLocationTooltip(type, tooltip);
}
static void appendValidTargetsTooltip(CustomisedSpellType<? extends ShieldSpell> type, List<Text> tooltip) { static final SpellAttribute<Boolean> TARGET_ITEMS = SpellAttribute.createConditional(SpellAttributes.PERMIT_ITEMS, Trait.KNOWLEDGE, knowledge -> knowledge > 10);
if (type.traits().get(Trait.KNOWLEDGE) > 10) { static final SpellAttribute<Boolean> PERMIT_PASSIVE = SpellAttribute.createConditional(SpellAttributes.PERMIT_PASSIVE, Trait.LIFE, l -> l > 0);
tooltip.add(SpellAttributes.PERMIT_ITEMS); static final SpellAttribute<Boolean> PERMIT_HOSTILE = SpellAttribute.createConditional(SpellAttributes.PERMIT_HOSTILE, Trait.BLOOD, l -> l > 0);
} else { static final SpellAttribute<Boolean> PERMIT_PLAYER = SpellAttribute.createConditional(SpellAttributes.PERMIT_PLAYER, Trait.ICE, l -> l > 0);
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 void appendCastLocationTooltip(CustomisedSpellType<?> type, List<Text> tooltip) { static final TooltipFactory PERMIT_ENTITY = TooltipFactory.of(PERMIT_PASSIVE, PERMIT_HOSTILE, PERMIT_PLAYER);
tooltip.add(type.traits().get(Trait.GENEROSITY) > 0 ? SpellAttributes.CAST_ON_LOCATION : SpellAttributes.CAST_ON_PERSON); 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); protected final TargetSelecter targetSelecter = new TargetSelecter(this).setFilter(this::isValidTarget);
@ -90,7 +78,7 @@ public class ShieldSpell extends AbstractSpell {
@Override @Override
public Spell prepareForCast(Caster<?> caster, CastingMethod method) { 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 @Override
@ -176,7 +164,7 @@ public class ShieldSpell extends AbstractSpell {
* Calculates the maximum radius of the shield. aka The area of effect. * Calculates the maximum radius of the shield. aka The area of effect.
*/ */
public double getDrawDropOffRange(Caster<?> source) { 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(); double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / rangeMultiplier.getValue();
return range; return range;
@ -184,7 +172,7 @@ public class ShieldSpell extends AbstractSpell {
protected boolean isValidTarget(Caster<?> source, Entity entity) { protected boolean isValidTarget(Caster<?> source, Entity entity) {
if (getTraits().get(Trait.KNOWLEDGE) > 10) { if (TARGET_ITEMS.get(getTraits())) {
return entity instanceof ItemEntity; return entity instanceof ItemEntity;
} }
@ -198,13 +186,13 @@ public class ShieldSpell extends AbstractSpell {
|| entity instanceof BoatEntity || entity instanceof BoatEntity
); );
if (getTraits().get(Trait.LIFE) > 0) { if (PERMIT_PASSIVE.get(getTraits())) {
valid &= !(entity instanceof PassiveEntity); valid &= !(entity instanceof PassiveEntity);
} }
if (getTraits().get(Trait.BLOOD) > 0) { if (PERMIT_HOSTILE.get(getTraits())) {
valid &= !(entity instanceof HostileEntity); valid &= !(entity instanceof HostileEntity);
} }
if (getTraits().get(Trait.ICE) > 0) { if (PERMIT_PLAYER.get(getTraits())) {
valid &= !(entity instanceof PlayerEntity); valid &= !(entity instanceof PlayerEntity);
} }
return valid; 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.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; 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.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.Pony; 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.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -41,10 +39,6 @@ import net.minecraft.util.math.Vec3d;
public class SiphoningSpell extends AbstractAreaEffectSpell { public class SiphoningSpell extends AbstractAreaEffectSpell {
static final Predicate<Entity> TARGET_PREDICATE = EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.and(EntityPredicates.VALID_LIVING_ENTITY); 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 final DataTracker.Entry<Boolean> upset = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private int ticksUpset; private int ticksUpset;
@ -65,7 +59,7 @@ public class SiphoningSpell extends AbstractAreaEffectSpell {
} }
if (source.isClient()) { 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; int direction = isFriendlyTogether(source) ? 1 : -1;
source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> { 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.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.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell; 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;
@ -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.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell; 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.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.UItems; 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<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<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<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<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(FireSpell::appendTooltip)); 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(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(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::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.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::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.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::appendTooltip2)); 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<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<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(SiphoningSpell::appendTooltip)); 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::appendTooltip)); 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<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<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<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<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::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.TOOLTIP));
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<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::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.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<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<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::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.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::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.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::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.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::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.TOOLTIP));
public static void bootstrap() {} public static void bootstrap() {}
@ -274,6 +276,12 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return this; 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) { public Builder<T> tooltip(BiConsumer<CustomisedSpellType<T>, List<Text>> tooltipFunction) {
this.tooltipFunction = tooltipFunction; this.tooltipFunction = tooltipFunction;
return this; return this;