Spells now have their own affinity and can only be used with gems of a matching type

This commit is contained in:
Sollace 2019-02-04 20:29:37 +02:00
parent 79e9b310d3
commit 0af6a52719
18 changed files with 173 additions and 61 deletions

View file

@ -1,10 +1,11 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.spell.IAligned;
import com.minelittlepony.unicopia.spell.SpellAffinity; import com.minelittlepony.unicopia.spell.SpellAffinity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
public interface IMagicalItem { public interface IMagicalItem extends IAligned {
/** /**
* If true this item serves as host to its own inner dimensional space. * If true this item serves as host to its own inner dimensional space.
* Bag of Holding will explode if you try to store items of this kind inside of it. * Bag of Holding will explode if you try to store items of this kind inside of it.
@ -18,6 +19,6 @@ public interface IMagicalItem {
* What this returns may have effects on the behaviour of certain spells and effects. * What this returns may have effects on the behaviour of certain spells and effects.
*/ */
default SpellAffinity getAffinity(ItemStack stack) { default SpellAffinity getAffinity(ItemStack stack) {
return SpellAffinity.NEUTRAL; return getAffinity();
} }
} }

View file

@ -52,7 +52,7 @@ public class ItemCurse extends ItemSpell {
} }
@Override @Override
public SpellAffinity getAffinity(ItemStack stack) { public SpellAffinity getAffinity() {
return SpellAffinity.BAD; return SpellAffinity.BAD;
} }
} }

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.Predicates;
import com.minelittlepony.unicopia.UClient; import com.minelittlepony.unicopia.UClient;
import com.minelittlepony.unicopia.inventory.ContainerOfHolding; import com.minelittlepony.unicopia.inventory.ContainerOfHolding;
import com.minelittlepony.unicopia.inventory.InventoryOfHolding; import com.minelittlepony.unicopia.inventory.InventoryOfHolding;
import com.minelittlepony.unicopia.spell.SpellAffinity;
import com.minelittlepony.util.vector.VecHelper; import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.client.util.ITooltipFlag; import net.minecraft.client.util.ITooltipFlag;
@ -121,6 +122,11 @@ public class ItemOfHolding extends Item implements IMagicalItem {
return new ActionResult<>(EnumActionResult.SUCCESS, stack); return new ActionResult<>(EnumActionResult.SUCCESS, stack);
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.NEUTRAL;
}
@Override @Override
public boolean hasInnerSpace() { public boolean hasInnerSpace() {
return true; return true;

View file

@ -184,7 +184,7 @@ public class ItemSpell extends Item implements ICastable {
if (SpellRegistry.stackHasEnchantment(stack)) { if (SpellRegistry.stackHasEnchantment(stack)) {
SpellAffinity affinity = getAffinity(stack); SpellAffinity affinity = getAffinity(stack);
tooltip.add(affinity.getColourCode() + I18n.format(String.format("%s.%s.name", tooltip.add(affinity.getColourCode() + I18n.format(String.format("%s.%s.tagline",
affinity.getTranslationKey(), affinity.getTranslationKey(),
SpellRegistry.getKeyFromStack(stack) SpellRegistry.getKeyFromStack(stack)
))); )));
@ -213,7 +213,7 @@ public class ItemSpell extends Item implements ICastable {
super.getSubItems(tab, subItems); super.getSubItems(tab, subItems);
if (isInCreativeTab(tab)) { if (isInCreativeTab(tab)) {
for (String name : SpellRegistry.instance().getAllNames()) { for (String name : SpellRegistry.instance().getAllNames(getAffinity())) {
subItems.add(SpellRegistry.instance().enchantStack(new ItemStack(this, 1), name)); subItems.add(SpellRegistry.instance().enchantStack(new ItemStack(this, 1), name));
} }
} }
@ -236,7 +236,7 @@ public class ItemSpell extends Item implements ICastable {
} }
@Override @Override
public SpellAffinity getAffinity(ItemStack stack) { public SpellAffinity getAffinity() {
return SpellAffinity.GOOD; return SpellAffinity.GOOD;
} }
} }

View file

@ -12,6 +12,11 @@ public abstract class AbstractSpell implements IMagicEffect {
@Override @Override
public void setCurrentLevel(int level) { public void setCurrentLevel(int level) {
}
@Override
public boolean isCraftable() {
return true;
} }
@Override @Override

View file

@ -0,0 +1,12 @@
package com.minelittlepony.unicopia.spell;
/**
* Interface for things that have an affine alignment.
*/
public interface IAligned {
/**
* Gets the current alignment.
* Good/Bad/Neutral
*/
SpellAffinity getAffinity();
}

View file

@ -15,14 +15,12 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelled { public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelled, IAligned {
void setEffect(IMagicEffect effect); void setEffect(IMagicEffect effect);
IMagicEffect getEffect(); IMagicEffect getEffect();
SpellAffinity getAffinity();
default boolean hasEffect() { default boolean hasEffect() {
return getEffect() != null; return getEffect() != null;
} }

View file

@ -5,7 +5,7 @@ import com.minelittlepony.unicopia.util.serialisation.InbtSerialisable;
/** /**
* Interface for a magic spells * Interface for a magic spells
*/ */
public interface IMagicEffect extends InbtSerialisable, ILevelled { public interface IMagicEffect extends InbtSerialisable, ILevelled, IAligned {
/** /**
* Gets the name used to identify this effect. * Gets the name used to identify this effect.
@ -27,6 +27,11 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled {
*/ */
boolean getDead(); boolean getDead();
/**
* Returns true if this effect can be crafted into a gem.
*/
boolean isCraftable();
/** /**
* Called when first attached to a gem. * Called when first attached to a gem.
*/ */

View file

@ -11,6 +11,8 @@ public enum SpellAffinity {
private final int corruption; private final int corruption;
private SpellAffinity[] implications;
SpellAffinity(TextFormatting color, int corruption) { SpellAffinity(TextFormatting color, int corruption) {
this.color = color; this.color = color;
this.corruption = corruption; this.corruption = corruption;
@ -31,4 +33,18 @@ public enum SpellAffinity {
public boolean isNeutral() { public boolean isNeutral() {
return this == NEUTRAL; return this == NEUTRAL;
} }
public SpellAffinity[] getImplicators() {
if (implications != null) {
return implications;
}
if (this == NEUTRAL) {
implications = values();
} else {
implications = new SpellAffinity[] { this };
}
return implications;
}
} }

View file

@ -32,6 +32,11 @@ public class SpellCharge extends AbstractSpell {
return "charge"; return "charge";
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
@Override @Override
public int getTint() { public int getTint() {
return 0x0000AA; return 0x0000AA;

View file

@ -31,6 +31,16 @@ public class SpellDisguise extends AbstractSpell {
return "disguise"; return "disguise";
} }
@Override
public boolean isCraftable() {
return false;
}
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.BAD;
}
@Override @Override
public int getTint() { public int getTint() {
return 0; return 0;

View file

@ -73,6 +73,11 @@ public class SpellFire extends AbstractSpell implements IUseAction, IDispenceabl
return "fire"; return "fire";
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
@Override @Override
public int getTint() { public int getTint() {
return 0xFF0000; return 0xFF0000;

View file

@ -61,6 +61,11 @@ public class SpellIce extends AbstractSpell implements IUseAction, IDispenceable
return "ice"; return "ice";
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
@Override @Override
public int getTint() { public int getTint() {
return 0xADD8E6; return 0xADD8E6;

View file

@ -67,6 +67,11 @@ public class SpellPortal extends AbstractSpell implements IUseAction {
return 0x384C38; return 0x384C38;
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
@Override @Override
public void setDead() { public void setDead() {
super.setDead(); super.setDead();

View file

@ -1,12 +1,15 @@
package com.minelittlepony.unicopia.spell; package com.minelittlepony.unicopia.spell;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@ -23,7 +26,9 @@ public class SpellRegistry {
return stack.hasTagCompound() && stack.getTagCompound().hasKey("spell"); return stack.hasTagCompound() && stack.getTagCompound().hasKey("spell");
} }
private final Map<String, Entry> entries = new HashMap<>(); private final Map<String, Entry<?>> entries = new HashMap<>();
private final Map<SpellAffinity, Set<String>> keysByAffinity = new HashMap<>();
private SpellRegistry() { private SpellRegistry() {
registerSpell(SpellShield::new); registerSpell(SpellShield::new);
@ -35,6 +40,7 @@ public class SpellRegistry {
registerSpell(SpellDisguise::new); registerSpell(SpellDisguise::new);
} }
@Nullable
public IMagicEffect getSpellFromName(String name) { public IMagicEffect getSpellFromName(String name) {
if (entries.containsKey(name)) { if (entries.containsKey(name)) {
return entries.get(name).create(); return entries.get(name).create();
@ -65,41 +71,28 @@ public class SpellRegistry {
return compound; return compound;
} }
private Optional<Entry<?>> getEntryFromStack(ItemStack stack) {
return Optional.ofNullable(entries.get(getKeyFromStack(stack)));
}
@Nullable @Nullable
public IDispenceable getDispenseActionFrom(ItemStack stack) { public IDispenceable getDispenseActionFrom(ItemStack stack) {
String key = getKeyFromStack(stack); return getEntryFromStack(stack).map(Entry::dispensable).orElse(null);
if (entries.containsKey(key)) {
Entry entry = entries.get(key);
if (entry.canDispense) {
return entry.create();
}
}
return null;
} }
@Nullable @Nullable
public IUseAction getUseActionFrom(ItemStack stack) { public IUseAction getUseActionFrom(ItemStack stack) {
String key = getKeyFromStack(stack); return getEntryFromStack(stack).map(Entry::useable).orElse(null);
if (entries.containsKey(key)) {
Entry entry = entries.get(key);
if (entry.canUse) {
return entry.create();
}
}
return null;
} }
@Nullable
public IMagicEffect getSpellFromItemStack(ItemStack stack) { public IMagicEffect getSpellFromItemStack(ItemStack stack) {
return getSpellFromName(getKeyFromStack(stack)); return getSpellFromName(getKeyFromStack(stack));
} }
public void registerSpell(Callable<IMagicEffect> factory) { public <T extends IMagicEffect> void registerSpell(Callable<T> factory) {
try { try {
new Entry(factory); new Entry<T>(factory);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -118,10 +111,7 @@ public class SpellRegistry {
} }
public ItemStack enchantStack(ItemStack stack, ItemStack from) { public ItemStack enchantStack(ItemStack stack, ItemStack from) {
stack.setTagCompound(new NBTTagCompound()); return enchantStack(stack, getKeyFromStack(from));
stack.getTagCompound().setString("spell", getKeyFromStack(from));
return stack;
} }
public ItemStack enchantStack(ItemStack stack, String name) { public ItemStack enchantStack(ItemStack stack, String name) {
@ -152,33 +142,58 @@ public class SpellRegistry {
return 0xffffff; return 0xffffff;
} }
public Set<String> getAllNames() { public Set<String> getAllNames(SpellAffinity affinity) {
return entries.keySet(); return keysByAffinity.get(affinity);
} }
class Entry { @Immutable
Callable<IMagicEffect> factory; class Entry<T extends IMagicEffect> {
final Callable<T> factory;
int color; final int color;
boolean canDispense; final boolean canDispense;
boolean canUse; final boolean canUse;
Entry(Callable<IMagicEffect> factory) throws Exception { final SpellAffinity affinity;
IMagicEffect inst = factory.call();
Entry(Callable<T> factory) throws Exception {
T inst = factory.call();
this.factory = factory; this.factory = factory;
this.color = inst.getTint(); this.color = inst.getTint();
this.canDispense = inst instanceof IDispenceable; this.canDispense = inst instanceof IDispenceable;
this.canUse = inst instanceof IUseAction; this.canUse = inst instanceof IUseAction;
this.affinity = inst.getAffinity();
if (inst.isCraftable()) {
for (SpellAffinity affinity : affinity.getImplicators()) {
keysByAffinity.computeIfAbsent(affinity, a -> new HashSet<>()).add(inst.getName());
}
}
entries.put(inst.getName(), this); entries.put(inst.getName(), this);
} }
@SuppressWarnings("unchecked") IUseAction useable() {
<T extends IMagicEffect> T create() { if (!canUse) {
return null;
}
return (IUseAction)create();
}
IDispenceable dispensable() {
if (!canDispense) {
return null;
}
return (IDispenceable)create();
}
T create() {
try { try {
return (T) factory.call(); return factory.call();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View file

@ -35,6 +35,11 @@ public class SpellShield extends AbstractSpell {
return "shield"; return "shield";
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.NEUTRAL;
}
@Override @Override
public int getTint() { public int getTint() {
return 0x66CDAA; return 0x66CDAA;

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.spell;
import com.minelittlepony.unicopia.UParticles; import com.minelittlepony.unicopia.UParticles;
import com.minelittlepony.unicopia.particle.Particles; import com.minelittlepony.unicopia.particle.Particles;
import com.minelittlepony.unicopia.player.PlayerSpeciesList; import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.util.MagicalDamageSource;
import com.minelittlepony.util.shape.Sphere; import com.minelittlepony.util.shape.Sphere;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -16,6 +17,11 @@ public class SpellVortex extends SpellShield {
return "vortex"; return "vortex";
} }
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.NEUTRAL;
}
@Override @Override
protected void spawnParticles(ICaster<?> source, int strength) { protected void spawnParticles(ICaster<?> source, int strength) {
Vec3d pos = source.getOriginVector(); Vec3d pos = source.getOriginVector();
@ -35,6 +41,10 @@ public class SpellVortex extends SpellShield {
force *= calculateAdjustedForce(PlayerSpeciesList.instance().getPlayer((EntityPlayer)target)); force *= calculateAdjustedForce(PlayerSpeciesList.instance().getPlayer((EntityPlayer)target));
} }
if (source.getAffinity() == SpellAffinity.BAD && source.getWorld().rand.nextInt(4500) == 0) {
source.getEntity().attackEntityFrom(MagicalDamageSource.create("vortex"), 4);
}
applyForce(pos, target, -force, 0); applyForce(pos, target, -force, 0);
float maxVel = source.getAffinity() == SpellAffinity.BAD ? 1 : 1.6f; float maxVel = source.getAffinity() == SpellAffinity.BAD ? 1 : 1.6f;

View file

@ -31,22 +31,31 @@ item.corrupted_gem.name=Fractured Gem
item.corrupted_gem.enchanted.name=Fractured Gem of %s item.corrupted_gem.enchanted.name=Fractured Gem of %s
spell.shield.name=Defense spell.shield.name=Defense
spell.charge.name=Chanelling spell.shield.tagline=Protection I
spell.fire.name=Flame
spell.infero.name=Burning
spell.ice.name=Frost
spell.portal.name=Transportation spell.portal.name=Transportation
spell.portal.tagline=Teleportation I
spell.fire.name=Flame
spell.fire.tagline=Fire I
spell.vortex.name=Retention spell.vortex.name=Retention
spell.minion.name=Obedience spell.vortex.tagline=Containment I
spell.charge.name=Chanelling
spell.charge.tagline=Energy I
spell.ice.name=Frost
spell.ice.tagline=Ice I
curse.shield.name=Repulsion curse.shield.name=Repulsion
curse.charge.name=Draining curse.shield.tagline=Hostility I
curse.fire.name=Hades
curse.inferno.name=Inferno curse.vortex.name=Suffering
curse.ice.name=Freezing curse.vortex.tagline=Torture I
curse.portal.name=Summoning
curse.attract.name=Entrapment curse.necromany.name=Necromancy
curse.minion.name=Slavery curse.necromancy.tagline=Resurrection I
item.spellbook.name=Spellbook item.spellbook.name=Spellbook
item.bag_of_holding.name=Bag of Holding item.bag_of_holding.name=Bag of Holding