More work on spells and gemstones

This commit is contained in:
Sollace 2021-03-02 15:40:37 +02:00
parent 4843a5c5f8
commit a58c6a0a44
28 changed files with 213 additions and 157 deletions

View file

@ -1,7 +1,5 @@
package com.minelittlepony.unicopia; package com.minelittlepony.unicopia;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
public enum Affinity { public enum Affinity {
@ -15,12 +13,14 @@ public enum Affinity {
private Affinity[] implications; private Affinity[] implications;
public static final Affinity[] VALUES = values();
Affinity(Formatting color, int corruption) { Affinity(Formatting color, int corruption) {
this.color = color; this.color = color;
this.corruption = corruption; this.corruption = corruption;
} }
public Formatting getColourCode() { public Formatting getColor() {
return color; return color;
} }
@ -28,10 +28,6 @@ public enum Affinity {
return this == BAD ? "curse" : "spell"; return this == BAD ? "curse" : "spell";
} }
public Text getName() {
return new TranslatableText("affinity." + getTranslationKey()).styled(s -> s.withColor(getColourCode()));
}
public int getCorruption() { public int getCorruption() {
return corruption; return corruption;
} }
@ -50,7 +46,7 @@ public enum Affinity {
} }
if (this == NEUTRAL) { if (this == NEUTRAL) {
implications = values(); implications = new Affinity[] { GOOD, BAD };
} else { } else {
implications = new Affinity[] { this }; implications = new Affinity[] { this };
} }
@ -58,12 +54,7 @@ public enum Affinity {
return implications; return implications;
} }
public static Affinity of(String s) { public static Affinity of(int ordinal, Affinity fallback) {
try { return ordinal < 0 || ordinal >= VALUES.length ? fallback : VALUES[ordinal];
if (s != null)
return valueOf(s.toUpperCase());
} catch (Throwable e) {}
return Affinity.NEUTRAL;
} }
} }

View file

@ -15,4 +15,8 @@ public interface Affine {
default boolean isEnemy(Affine other) { default boolean isEnemy(Affine other) {
return !getAffinity().alignsWith(other.getAffinity()); return !getAffinity().alignsWith(other.getAffinity());
} }
default boolean isFriendlyTogether(Affine other) {
return getAffinity() != Affinity.BAD && other.getAffinity() != Affinity.BAD;
}
} }

View file

@ -1,6 +1,5 @@
package com.minelittlepony.unicopia.ability.magic; package com.minelittlepony.unicopia.ability.magic;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -83,11 +82,6 @@ public interface Spell extends NbtSerialisable, Affine {
*/ */
void render(Caster<?> source); void render(Caster<?> source);
@Override
default Affinity getAffinity() {
return getType().getAffinity();
}
/** /**
* Return true to allow the gem update and move. * Return true to allow the gem update and move.
*/ */

View file

@ -1,12 +1,13 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Attached;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
public abstract class AbstractRangedAreaSpell extends AbstractSpell implements Attached { public abstract class AbstractRangedAreaSpell extends AbstractSpell implements Attached {
protected AbstractRangedAreaSpell(SpellType<?> type) { protected AbstractRangedAreaSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
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;
@ -12,8 +13,11 @@ public abstract class AbstractSpell implements Spell {
private final SpellType<?> type; private final SpellType<?> type;
protected AbstractSpell(SpellType<?> type) { private Affinity affinity;
protected AbstractSpell(SpellType<?> type, Affinity affinity) {
this.type = type; this.type = type;
this.affinity = affinity;
} }
@Override @Override
@ -56,14 +60,21 @@ public abstract class AbstractSpell implements Spell {
return 0; return 0;
} }
@Override
public Affinity getAffinity() {
return affinity;
}
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
compound.putBoolean("dead", isDead); compound.putBoolean("dead", isDead);
compound.putInt("affinity", affinity.ordinal());
} }
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
setDirty(false); setDirty(false);
isDead = compound.getBoolean("dead"); isDead = compound.getBoolean("dead");
affinity = Affinity.of(compound.getInt("affinity"), getType().getAffinity());
} }
} }

View file

@ -26,8 +26,8 @@ public class AttractiveSpell extends ShieldSpell implements Thrown {
@Nullable @Nullable
private BlockPos homingPos; private BlockPos homingPos;
protected AttractiveSpell(SpellType<?> type) { protected AttractiveSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override
@ -61,17 +61,19 @@ public class AttractiveSpell extends ShieldSpell implements Thrown {
double force = 2.5F * distance; double force = 2.5F * distance;
if (source.getAffinity() != Affinity.BAD && target instanceof PlayerEntity) { boolean isGood = isFriendlyTogether(source);
if (isGood && target instanceof PlayerEntity) {
force *= calculateAdjustedForce(Pony.of((PlayerEntity)target)); force *= calculateAdjustedForce(Pony.of((PlayerEntity)target));
} }
if (source.getAffinity() == Affinity.BAD && source.getWorld().random.nextInt(4500) == 0) { if (!isGood && source.getWorld().random.nextInt(4500) == 0) {
source.getEntity().damage(MagicalDamageSource.create("vortex"), 4); source.getEntity().damage(MagicalDamageSource.create("vortex"), 4);
} }
applyForce(pos, target, -force, 0); applyForce(pos, target, -force, 0);
float maxVel = source.getAffinity() == Affinity.BAD ? 1 : 1.6f; float maxVel = !isFriendlyTogether(source) ? 1 : 1.6f;
Vec3d vel = target.getVelocity(); Vec3d vel = target.getVelocity();

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.ability.magic.Thrown;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
@ -17,8 +18,8 @@ import net.minecraft.util.registry.Registry;
public class AwkwardSpell extends AbstractSpell implements Thrown { public class AwkwardSpell extends AbstractSpell implements Thrown {
protected AwkwardSpell(SpellType<?> type) { protected AwkwardSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -4,6 +4,7 @@ import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.FlightType;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Attached;
@ -31,8 +32,8 @@ public class DisguiseSpell extends AbstractSpell implements Attached, Suppressab
private int suppressionCounter; private int suppressionCounter;
protected DisguiseSpell(SpellType<?> type) { protected DisguiseSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Magical; import com.minelittlepony.unicopia.ability.magic.Magical;
@ -39,8 +40,8 @@ public class FireSpell extends AbstractRangedAreaSpell implements Thrown {
private static final Shape VISUAL_EFFECT_RANGE = new Sphere(false, 0.5); private static final Shape VISUAL_EFFECT_RANGE = new Sphere(false, 0.5);
private static final Shape EFFECT_RANGE = new Sphere(false, 4); private static final Shape EFFECT_RANGE = new Sphere(false, 4);
protected FireSpell(SpellType<?> type) { protected FireSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,12 +1,13 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
public class GenericSpell extends AbstractSpell { public class GenericSpell extends AbstractSpell {
protected GenericSpell(SpellType<?> type) { protected GenericSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.ability.magic.Thrown;
import com.minelittlepony.unicopia.block.state.StateMaps; import com.minelittlepony.unicopia.block.state.StateMaps;
@ -28,8 +29,8 @@ public class IceSpell extends AbstractRangedAreaSpell implements Thrown {
private final int rad = 3; private final int rad = 3;
private final Shape effect_range = new Sphere(false, rad); private final Shape effect_range = new Sphere(false, rad);
protected IceSpell(SpellType<?> type) { protected IceSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.block.state.StateMaps; import com.minelittlepony.unicopia.block.state.StateMaps;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
@ -16,8 +17,8 @@ import net.minecraft.world.World;
public class InfernoSpell extends FireSpell { public class InfernoSpell extends FireSpell {
protected InfernoSpell(SpellType<?> type) { protected InfernoSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.ability.magic.Thrown;
@ -29,9 +30,8 @@ public class JoustingSpell extends AbstractRangedAreaSpell implements Thrown {
private int age; private int age;
protected JoustingSpell(SpellType<?> type) { protected JoustingSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
// TODO Auto-generated constructor stub
} }
@Override @Override

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List; import java.util.List;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.WorldEvent;
import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Shape;
@ -25,8 +26,8 @@ public class NecromancySpell extends AbstractRangedAreaSpell {
EntityType.ZOMBIFIED_PIGLIN EntityType.ZOMBIFIED_PIGLIN
); );
protected NecromancySpell(SpellType<?> type) { protected NecromancySpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override
@ -36,7 +37,6 @@ public class NecromancySpell extends AbstractRangedAreaSpell {
return true; return true;
} }
float additional = source.getWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty(); float additional = source.getWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty();
int radius = source.getLevel().get() + 1; int radius = source.getLevel().get() + 1;
@ -61,7 +61,7 @@ public class NecromancySpell extends AbstractRangedAreaSpell {
if (source.getWorld().isAir(loc.up()) && !source.getWorld().isAir(loc)) { if (source.getWorld().isAir(loc.up()) && !source.getWorld().isAir(loc)) {
spawnMonster(source, pos); spawnMonster(source, pos);
return true; return false;
} }
} }
@ -72,8 +72,8 @@ public class NecromancySpell extends AbstractRangedAreaSpell {
protected void spawnMonster(Caster<?> source, Vec3d pos) { protected void spawnMonster(Caster<?> source, Vec3d pos) {
int index = (int)MathHelper.nextDouble(source.getWorld().random, 0, spawns.size()); int index = (int)MathHelper.nextDouble(source.getWorld().random, 0, spawns.size());
LivingEntity zombie = spawns.get(index).create(source.getWorld()); LivingEntity zombie = spawns.get(index).create(source.getWorld());
zombie.setPos(pos.x, pos.y, pos.z);
zombie.updatePositionAndAngles(pos.x, pos.y, pos.z, 0, 0);
zombie.setVelocity(0, 0.3, 0); zombie.setVelocity(0, 0.3, 0);
source.getWorld().syncWorldEvent(WorldEvent.ZOMBIE_BREAK_WOODEN_DOOR, zombie.getBlockPos(), 0); source.getWorld().syncWorldEvent(WorldEvent.ZOMBIE_BREAK_WOODEN_DOOR, zombie.getBlockPos(), 0);

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Suppressable; import com.minelittlepony.unicopia.ability.magic.Suppressable;
import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.ability.magic.Thrown;
@ -15,9 +16,10 @@ import net.minecraft.util.math.Vec3d;
* A spell for revealing changelings. * A spell for revealing changelings.
*/ */
public class RevealingSpell extends AbstractSpell implements Thrown { public class RevealingSpell extends AbstractSpell implements Thrown {
private static final Shape AREA = new Sphere(false, 15);
protected RevealingSpell(SpellType<?> type) { protected RevealingSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override
@ -41,11 +43,9 @@ public class RevealingSpell extends AbstractSpell implements Thrown {
@Override @Override
public void render(Caster<?> source) { public void render(Caster<?> source) {
Shape area = new Sphere(false, 15);
MagicParticleEffect effect = new MagicParticleEffect(getType().getColor()); MagicParticleEffect effect = new MagicParticleEffect(getType().getColor());
source.spawnParticles(area, 5, pos -> { source.spawnParticles(AREA, 5, pos -> {
source.addParticle(effect, pos, Vec3d.ZERO); source.addParticle(effect, pos, Vec3d.ZERO);
}); });
source.spawnParticles(effect, 5); source.spawnParticles(effect, 5);

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.block.state.StateMaps; import com.minelittlepony.unicopia.block.state.StateMaps;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
@ -16,8 +17,8 @@ import net.minecraft.util.math.Vec3d;
public class ScorchSpell extends FireSpell { public class ScorchSpell extends FireSpell {
protected ScorchSpell(SpellType<?> type) { protected ScorchSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override

View file

@ -39,8 +39,8 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
private final Map<UUID, Target> targets = new TreeMap<>(); private final Map<UUID, Target> targets = new TreeMap<>();
protected ShieldSpell(SpellType<?> type) { protected ShieldSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override
@ -101,7 +101,7 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
Entity owner = source.getMaster(); Entity owner = source.getMaster();
boolean ownerIsValid = source.getAffinity() != Affinity.BAD && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking()); boolean ownerIsValid = isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking());
return source.findAllEntitiesInRange(radius) return source.findAllEntitiesInRange(radius)
.filter(entity -> { .filter(entity -> {
@ -157,7 +157,7 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
} else if (target instanceof LivingEntity) { } else if (target instanceof LivingEntity) {
double force = Math.max(0.1, radius / 4); double force = Math.max(0.1, radius / 4);
if (source.getAffinity() != Affinity.BAD && target instanceof PlayerEntity) { if (isFriendlyTogether(source) && target instanceof PlayerEntity) {
force *= calculateAdjustedForce(Pony.of((PlayerEntity)target)); force *= calculateAdjustedForce(Pony.of((PlayerEntity)target));
} else { } else {
force *= 0.75; force *= 0.75;

View file

@ -23,8 +23,8 @@ import net.minecraft.util.math.Vec3d;
*/ */
public class SiphoningSpell extends AbstractRangedAreaSpell implements Thrown { public class SiphoningSpell extends AbstractRangedAreaSpell implements Thrown {
protected SiphoningSpell(SpellType<?> type) { protected SiphoningSpell(SpellType<?> type, Affinity affinity) {
super(type); super(type, affinity);
} }
@Override @Override
@ -41,7 +41,7 @@ public class SiphoningSpell extends AbstractRangedAreaSpell implements Thrown {
DamageSource damage = damageSource(owner); DamageSource damage = damageSource(owner);
if (source.getAffinity() == Affinity.BAD) { if (!isFriendlyTogether(source)) {
if (owner != null) { if (owner != null) {
float healthGain = 0; float healthGain = 0;
float maxHealthGain = owner.getMaxHealth() - owner.getHealth(); float maxHealthGain = owner.getMaxHealth() - owner.getHealth();
@ -108,7 +108,7 @@ public class SiphoningSpell extends AbstractRangedAreaSpell implements Thrown {
int radius = 4 + source.getLevel().get(); int radius = 4 + source.getLevel().get();
Vec3d origin = source.getOriginVector(); Vec3d origin = source.getOriginVector();
int direction = source.getAffinity() == Affinity.GOOD ? 1 : -1; int direction = !isEnemy(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 -> {
if (!source.getWorld().isAir(new BlockPos(pos).down())) { if (!source.getWorld().isAir(new BlockPos(pos).down())) {

View file

@ -5,11 +5,11 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -18,37 +18,37 @@ import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
public class SpellType<T extends Spell> { public class SpellType<T extends Spell> implements Affine {
public static final Identifier EMPTY_ID = new Identifier("unicopia", "null"); public static final Identifier EMPTY_ID = new Identifier("unicopia", "null");
public static final SpellType<?> EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, t -> null); public static final SpellType<?> EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, (t, a) -> null);
private static final Map<Identifier, SpellType<?>> REGISTRY = new HashMap<>(); private static final Map<Identifier, SpellType<?>> REGISTRY = new HashMap<>();
private static final Map<Affinity, Set<SpellType<?>>> BY_AFFINITY = new EnumMap<>(Affinity.class); private static final Map<Affinity, Set<SpellType<?>>> BY_AFFINITY = new EnumMap<>(Affinity.class);
public static final SpellType<IceSpell> ICE = register("ice", Affinity.GOOD, 0xBDBDF9, true, IceSpell::new); public static final SpellType<IceSpell> FROST = register("frost", Affinity.GOOD, 0xBDBDF9, true, IceSpell::new);
public static final SpellType<FireSpell> FIRE = register("fire", Affinity.GOOD, 0xFF5D00, true, FireSpell::new);
public static final SpellType<InfernoSpell> INFERNO = register("inferno", Affinity.BAD, 0xF00F00, true, InfernoSpell::new);
public static final SpellType<ScorchSpell> SCORCH = register("scorch", Affinity.BAD, 0, true, ScorchSpell::new); public static final SpellType<ScorchSpell> SCORCH = register("scorch", Affinity.BAD, 0, true, ScorchSpell::new);
public static final SpellType<FireSpell> FLAME = register("flame", Affinity.GOOD, 0xFF5D00, true, FireSpell::new);
public static final SpellType<InfernoSpell> INFERNAL = register("infernal", Affinity.BAD, 0xF00F00, true, InfernoSpell::new);
public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell::new); public static final SpellType<ShieldSpell> SHIELD = register("shield", Affinity.NEUTRAL, 0x66CDAA, true, ShieldSpell::new);
public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0x4CDEE7, true, AttractiveSpell::new); public static final SpellType<AttractiveSpell> VORTEX = register("vortex", Affinity.NEUTRAL, 0x4CDEE7, true, AttractiveSpell::new);
public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0x3A3A3A, true, NecromancySpell::new); public static final SpellType<NecromancySpell> NECROMANCY = register("necromancy", Affinity.BAD, 0x3A3A3A, true, NecromancySpell::new);
public static final SpellType<SiphoningSpell> SIPHONING = register("siphon", Affinity.NEUTRAL, 0xe308ab, true, SiphoningSpell::new); public static final SpellType<SiphoningSpell> SIPHONING = register("siphoning", Affinity.NEUTRAL, 0xe308ab, true, SiphoningSpell::new);
public static final SpellType<DisguiseSpell> DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, DisguiseSpell::new); public static final SpellType<DisguiseSpell> DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, DisguiseSpell::new);
public static final SpellType<RevealingSpell> REVEALING = register("reveal", Affinity.GOOD, 0x5CE81F, true, RevealingSpell::new); public static final SpellType<RevealingSpell> REVEALING = register("reveal", Affinity.GOOD, 0x5CE81F, true, RevealingSpell::new);
public static final SpellType<JoustingSpell> JOUSTING = register("joust", Affinity.GOOD, 0xBDBDF9, false, JoustingSpell::new); public static final SpellType<JoustingSpell> JOUSTING = register("joust", Affinity.GOOD, 0xBDBDF9, false, JoustingSpell::new);
public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.NEUTRAL, 0xE1239C, true, AwkwardSpell::new); public static final SpellType<AwkwardSpell> AWKWARD = register("awkward", Affinity.GOOD, 0xE1239C, true, AwkwardSpell::new);
final Identifier id;
final Affinity affinity;
final int color;
final boolean obtainable;
final Function<SpellType<?>, T> factory; private final Identifier id;
private final Affinity affinity;
private final int color;
private final boolean obtainable;
@Nullable private final Factory<T> factory;
private String translationKey;
SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Function<SpellType<?>, T> factory) { private final Map<Affinity, String> translationKeys = new EnumMap<>(Affinity.class);
SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
this.id = id; this.id = id;
this.affinity = affinity; this.affinity = affinity;
this.color = color; this.color = color;
@ -71,25 +71,28 @@ public class SpellType<T extends Spell> {
return color; return color;
} }
@Override
public Affinity getAffinity() { public Affinity getAffinity() {
return affinity; return affinity;
} }
public String getTranslationKey() { public String getTranslationKey(Affinity affinity) {
if (translationKey == null) { return translationKeys.computeIfAbsent(affinity, a -> Util.createTranslationKey(a.getTranslationKey(), getId()));
translationKey = Util.createTranslationKey("spell", getId());
}
return translationKey;
} }
public Text getName() { public Text getName(Affinity affinity) {
return new TranslatableText(getTranslationKey()); return new TranslatableText(getTranslationKey(affinity));
} }
@Nullable @Nullable
public T create() { public T create() {
return create(getAffinity());
}
@Nullable
public T create(Affinity affinity) {
try { try {
return factory.apply(this); return factory.create(this, affinity);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -97,18 +100,18 @@ public class SpellType<T extends Spell> {
return null; return null;
} }
public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, Function<SpellType<?>, T> factory) { public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
SpellType<T> type = new SpellType<>(id, affinity, color, obtainable, factory); SpellType<T> type = new SpellType<>(id, affinity, color, obtainable, factory);
for (Affinity i : affinity.getImplicators()) { for (Affinity i : affinity.getImplicators()) {
BY_AFFINITY.computeIfAbsent(i, a -> new HashSet<>()).add(type); byAffinity(i).add(type);
} }
REGISTRY.put(id, type); REGISTRY.put(id, type);
return type; return type;
} }
public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, Function<SpellType<?>, T> factory) { public static <T extends Spell> SpellType<T> register(String name, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
return register(new Identifier("unicopia", name), affinity, color, obtainable, factory); return register(new Identifier("unicopia", name), affinity, color, obtainable, factory);
} }
@ -118,7 +121,7 @@ public class SpellType<T extends Spell> {
} }
public static Set<SpellType<?>> byAffinity(Affinity affinity) { public static Set<SpellType<?>> byAffinity(Affinity affinity) {
return BY_AFFINITY.get(affinity); return BY_AFFINITY.computeIfAbsent(affinity, a -> new HashSet<>());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -148,4 +151,8 @@ public class SpellType<T extends Spell> {
return compound; return compound;
} }
public interface Factory<T extends Spell> {
T create(SpellType<T> type, Affinity affinity);
}
} }

View file

@ -17,6 +17,7 @@ import com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer;
import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer; import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer;
import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer; import com.minelittlepony.unicopia.client.render.WingsFeatureRenderer;
import com.minelittlepony.unicopia.item.ChameleonItem; import com.minelittlepony.unicopia.item.ChameleonItem;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry;
@ -24,6 +25,7 @@ import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry.Pendin
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry; import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.SpriteProvider; import net.minecraft.client.particle.SpriteProvider;
@ -36,6 +38,7 @@ import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.DyeableItem; import net.minecraft.item.DyeableItem;
import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleEffect;
import net.minecraft.util.Identifier;
public interface URenderers { public interface URenderers {
static void bootstrap() { static void bootstrap() {
@ -89,6 +92,12 @@ public interface URenderers {
matrices.push(); matrices.push();
}); });
FabricModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity) -> {
return GemstoneItem.isEnchanted(stack) ? 1 + GemstoneItem.getAffinity(stack).ordinal() : 0;
});
ColorProviderRegistry.ITEM.register((stack, i) -> {
return i > 0 || !GemstoneItem.isEnchanted(stack) ? -1 : GemstoneItem.getSpellKey(stack).getColor();
}, UItems.GEMSTONE);
} }
static <T extends ParticleEffect> PendingParticleFactory<T> createFactory(ParticleSupplier<T> supplier) { static <T extends ParticleEffect> PendingParticleFactory<T> createFactory(ParticleSupplier<T> supplier) {

View file

@ -31,19 +31,28 @@ public class GemstoneItem extends Item {
@Override @Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> list, TooltipContext tooltipContext) { public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> list, TooltipContext tooltipContext) {
if (isEnchanted(stack)) {
SpellType<?> key = getSpellKey(stack);
Affinity affinity = getAffinity(stack);
list.add(new TranslatableText(key.getTranslationKey(affinity) + ".lore").formatted(affinity.getColor()));
}
} }
@Override @Override
public void appendStacks(ItemGroup tab, DefaultedList<ItemStack> items) { public void appendStacks(ItemGroup tab, DefaultedList<ItemStack> items) {
super.appendStacks(tab, items); super.appendStacks(tab, items);
if (isIn(tab)) { if (isIn(tab)) {
SpellType.byAffinity(Affinity.GOOD).forEach(type -> { for (Affinity i : Affinity.VALUES) {
SpellType.byAffinity(i).forEach(type -> {
if (type.isObtainable()) { if (type.isObtainable()) {
items.add(enchanted(getDefaultStack(), type)); items.add(enchanted(getDefaultStack(), type, i));
} }
}); });
} }
} }
}
@Override @Override
public boolean hasGlint(ItemStack stack) { public boolean hasGlint(ItemStack stack) {
@ -53,7 +62,7 @@ public class GemstoneItem extends Item {
@Override @Override
public Text getName(ItemStack stack) { public Text getName(ItemStack stack) {
if (isEnchanted(stack)) { if (isEnchanted(stack)) {
return new TranslatableText(getTranslationKey(stack) + ".enchanted", getSpellKey(stack).getName()); return new TranslatableText(getTranslationKey(stack) + ".enchanted", getSpellKey(stack).getName(getAffinity(stack)));
} }
return super.getName(); return super.getName();
} }
@ -61,11 +70,11 @@ public class GemstoneItem extends Item {
public static Stream<Spell> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType<?> exclude, Predicate<Spell> test) { public static Stream<Spell> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType<?> exclude, Predicate<Spell> test) {
SpellType<Spell> key = GemstoneItem.getSpellKey(stack); SpellType<Spell> key = GemstoneItem.getSpellKey(stack);
if (key == null || Objects.equals(key, exclude)) { if (Objects.equals(key, exclude)) {
return Stream.empty(); return Stream.empty();
} }
Spell spell = key.create(); Spell spell = key.create(getAffinity(stack));
if (spell == null || !test.test(spell)) { if (spell == null || !test.test(spell)) {
return Stream.empty(); return Stream.empty();
@ -87,23 +96,31 @@ public class GemstoneItem extends Item {
} }
public static ItemStack enchanted(ItemStack stack, SpellType<?> type) { public static ItemStack enchanted(ItemStack stack, SpellType<?> type) {
return enchanted(stack, type, type.getAffinity());
}
public static ItemStack enchanted(ItemStack stack, SpellType<?> type, Affinity affinity) {
stack.getOrCreateTag().putString("spell", type.getId().toString()); stack.getOrCreateTag().putString("spell", type.getId().toString());
stack.getOrCreateTag().putInt("affinity", affinity.ordinal());
return stack; return stack;
} }
public static ItemStack unenchanted(ItemStack stack) { public static ItemStack unenchanted(ItemStack stack) {
if (isEnchanted(stack)) { stack.removeSubTag("spell");
stack.getTag().remove("spell"); stack.removeSubTag("affinity");
if (stack.getTag().isEmpty()) {
stack.setTag(null);
}
}
return stack; return stack;
} }
public static <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) { public static <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getTag().getString("spell")) : SpellType.EMPTY_ID); return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getTag().getString("spell")) : SpellType.EMPTY_ID);
} }
public static Affinity getAffinity(ItemStack stack) {
Affinity fallback = getSpellKey(stack).getAffinity();
if (stack.hasTag() && stack.getTag().contains("affinity")) {
return Affinity.of(stack.getTag().getInt("affinity"), fallback);
}
return fallback;
}
} }

View file

@ -76,8 +76,11 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
protected Item getDefaultItem() { protected Item getDefaultItem() {
Spell spell = this.getSpell(false); switch (getSpellOrEmpty(Spell.class, false).map(Spell::getAffinity).orElse(Affinity.NEUTRAL)) {
return spell == null ? Items.AIR : spell.getAffinity() == Affinity.BAD ? Items.MAGMA_CREAM : Items.SNOWBALL; case GOOD: return Items.SNOWBALL;
case BAD: return Items.MAGMA_CREAM;
default: return Items.AIR;
}
} }
@Override @Override
@ -107,7 +110,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
public Affinity getAffinity() { public Affinity getAffinity() {
return hasSpell() ? Affinity.NEUTRAL : getSpell(true).getAffinity(); return hasSpell() ? getSpell(true).getAffinity() : Affinity.NEUTRAL;
} }
@Override @Override

View file

@ -92,60 +92,44 @@
"item.minecraft.lingering_potion.effect.unicopia.tribe_swap_bat": "Lingering Potion of Bat Pony Metamorphosis", "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_bat": "Lingering Potion of Bat Pony Metamorphosis",
"item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_bat": "Arrow of Bat Pony Metamorphosis", "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_bat": "Arrow of Bat Pony Metamorphosis",
"affinity.good": "Pure", "spell.unicopia.frost": "Frost",
"affinity.neutral": "Neutral", "spell.unicopia.frost.lore": "Ice I",
"affinity.curse": "Corrupt",
"curse.unicopia.scorch": "Scorching",
"curse.unicopia.scorch.lore": "Fire I",
"spell.unicopia.flame": "Flaming",
"spell.unicopia.flame.lore": "Fire II",
"curse.unicopia.infernal": "Infernal",
"curse.unicopia.infernal.lore": "Fire III",
"spell.unicopia.shield": "Protective", "spell.unicopia.shield": "Protective",
"spell.unicopia.shield.tagline": "Protection I", "spell.unicopia.shield.lore": "Protection I",
"spell.unicopia.awkward": "Unstable",
"spell.unicopia.awkward.tagline": "*Derp*",
"spell.unicopia.light": "Illumination",
"spell.unicopia.light.tagline": "Discovery I",
"spell.unicopia.reveal": "Revealing",
"spell.unicopia.reveal.tagline": "Discovery II",
"spell.unicopia.flame": "Burning",
"spell.unicopia.flame.tagline": "Fire I",
"spell.unicopia.fire": "Flaming",
"spell.unicopia.fire.tagline": "Fire II",
"spell.unicopia.vortex": "Retention",
"spell.unicopia.vortex.tagline": "Containment I",
"spell.unicopia.siphon": "Siphoning",
"spell.unicopia.siphon.tagline": "Energy II",
"spell.unicopia.ice": "Frost",
"spell.unicopia.ice.tagline": "Ice I",
"curse.unicopia.shield": "Repulsive", "curse.unicopia.shield": "Repulsive",
"curse.unicopia.shield.tagline": "Hostility I", "curse.unicopia.shield.lore": "Hostility I",
"curse.unicopia.darkness": "Dark", "spell.unicopia.vortex": "Attractive",
"curse.unicopia.darkness.tagline": "Golomancy I/Resurrection II", "spell.unicopia.vortex.lore": "Containment I",
"curse.unicopia.harm": "Harmful",
"curse.unicopia.harm.tagline": "Hostility II",
"curse.unicopia.awkward": "Awkward",
"curse.unicopia.awkward.tagline": "*Derp*",
"curse.unicopia.vortex": "Suffering", "curse.unicopia.vortex": "Suffering",
"curse.unicopia.vortex.tagline": "Torture I", "curse.unicopia.vortex.lore": "Torture I",
"curse.unicopia.necromancy": "Resurrection", "curse.unicopia.necromancy": "Resurrection",
"curse.unicopia.necromancy.tagline": "Resurrection I", "curse.unicopia.necromancy.lore": "Resurrection I",
"curse.unicopia.inferno": "Inferno", "spell.unicopia.siphoning": "Siphoning",
"curse.unicopia.inferno.tagline": "Fire III", "spell.unicopia.siphoning.lore": "Energy II",
"curse.unicopia.siphon": "Siphoning", "curse.unicopia.siphoning": "Siphoning",
"curse.unicopia.siphon.tagline": "Energy III", "curse.unicopia.siphoning.lore": "Energy III",
"spell.unicopia.reveal": "Revealing",
"spell.unicopia.reveal.lore": "Discovery II",
"spell.unicopia.awkward": "Unstable",
"spell.unicopia.awkward.lore": "Chaos I",
"toxicity.safe.name": "Safe", "toxicity.safe.name": "Safe",
"toxicity.mild.name": "Mildly Toxic", "toxicity.mild.name": "Mildly Toxic",

View file

@ -2,5 +2,19 @@
"parent": "item/generated", "parent": "item/generated",
"textures": { "textures": {
"layer0": "unicopia:item/gemstone" "layer0": "unicopia:item/gemstone"
},
"overrides": [
{
"predicate": {
"affinity": 1
},
"model": "unicopia:item/gemstone_pure"
},
{
"predicate": {
"affinity": 3
},
"model": "unicopia:item/gemstone_corrupted"
} }
]
} }

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/gemstone_corrupted"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/gemstone_pure"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB