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;
import com.minelittlepony.unicopia.spell.IAligned;
import com.minelittlepony.unicopia.spell.SpellAffinity;
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.
* 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.
*/
default SpellAffinity getAffinity(ItemStack stack) {
return SpellAffinity.NEUTRAL;
return getAffinity();
}
}

View file

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

View file

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

View file

@ -184,7 +184,7 @@ public class ItemSpell extends Item implements ICastable {
if (SpellRegistry.stackHasEnchantment(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(),
SpellRegistry.getKeyFromStack(stack)
)));
@ -213,7 +213,7 @@ public class ItemSpell extends Item implements ICastable {
super.getSubItems(tab, subItems);
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));
}
}
@ -236,7 +236,7 @@ public class ItemSpell extends Item implements ICastable {
}
@Override
public SpellAffinity getAffinity(ItemStack stack) {
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
}

View file

@ -12,6 +12,11 @@ public abstract class AbstractSpell implements IMagicEffect {
@Override
public void setCurrentLevel(int level) {
}
@Override
public boolean isCraftable() {
return true;
}
@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.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);
IMagicEffect getEffect();
SpellAffinity getAffinity();
default boolean hasEffect() {
return getEffect() != null;
}

View file

@ -5,7 +5,7 @@ import com.minelittlepony.unicopia.util.serialisation.InbtSerialisable;
/**
* 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.
@ -27,6 +27,11 @@ public interface IMagicEffect extends InbtSerialisable, ILevelled {
*/
boolean getDead();
/**
* Returns true if this effect can be crafted into a gem.
*/
boolean isCraftable();
/**
* Called when first attached to a gem.
*/

View file

@ -11,6 +11,8 @@ public enum SpellAffinity {
private final int corruption;
private SpellAffinity[] implications;
SpellAffinity(TextFormatting color, int corruption) {
this.color = color;
this.corruption = corruption;
@ -31,4 +33,18 @@ public enum SpellAffinity {
public boolean isNeutral() {
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";
}
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.GOOD;
}
@Override
public int getTint() {
return 0x0000AA;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.spell;
import com.minelittlepony.unicopia.UParticles;
import com.minelittlepony.unicopia.particle.Particles;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.util.MagicalDamageSource;
import com.minelittlepony.util.shape.Sphere;
import net.minecraft.entity.Entity;
@ -16,6 +17,11 @@ public class SpellVortex extends SpellShield {
return "vortex";
}
@Override
public SpellAffinity getAffinity() {
return SpellAffinity.NEUTRAL;
}
@Override
protected void spawnParticles(ICaster<?> source, int strength) {
Vec3d pos = source.getOriginVector();
@ -35,6 +41,10 @@ public class SpellVortex extends SpellShield {
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);
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
spell.shield.name=Defense
spell.charge.name=Chanelling
spell.fire.name=Flame
spell.infero.name=Burning
spell.ice.name=Frost
spell.shield.tagline=Protection I
spell.portal.name=Transportation
spell.portal.tagline=Teleportation I
spell.fire.name=Flame
spell.fire.tagline=Fire I
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.charge.name=Draining
curse.fire.name=Hades
curse.inferno.name=Inferno
curse.ice.name=Freezing
curse.portal.name=Summoning
curse.attract.name=Entrapment
curse.minion.name=Slavery
curse.shield.tagline=Hostility I
curse.vortex.name=Suffering
curse.vortex.tagline=Torture I
curse.necromany.name=Necromancy
curse.necromancy.tagline=Resurrection I
item.spellbook.name=Spellbook
item.bag_of_holding.name=Bag of Holding