mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-17 10:24:23 +01:00
Spells can now be attached to entities other than players
This commit is contained in:
parent
1248b93995
commit
779ae10a99
17 changed files with 289 additions and 81 deletions
|
@ -1,8 +1,10 @@
|
||||||
package com.minelittlepony.unicopia.forgebullshit;
|
package com.minelittlepony.unicopia.forgebullshit;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
|
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.item.EntityItem;
|
import net.minecraft.entity.item.EntityItem;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
@ -28,9 +30,11 @@ public class FBS {
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void attach(AttachCapabilitiesEvent<Entity> event) {
|
public static void attach(AttachCapabilitiesEvent<Entity> event) {
|
||||||
if (event.getObject() instanceof EntityPlayer
|
Entity obj = event.getObject();
|
||||||
|| event.getObject() instanceof EntityItem) {
|
|
||||||
event.addCapability(new ResourceLocation("unicopia", "race"), new Provider(event.getObject()));
|
if ((obj instanceof EntityLivingBase && !(obj instanceof IMagicals))
|
||||||
|
|| obj instanceof EntityItem) {
|
||||||
|
event.addCapability(new ResourceLocation("unicopia", "race"), new Provider(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Predicates;
|
import com.minelittlepony.unicopia.Predicates;
|
||||||
import com.minelittlepony.unicopia.power.IPower;
|
import com.minelittlepony.unicopia.player.IPlayer;
|
||||||
|
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||||
import com.minelittlepony.unicopia.spell.CasterUtils;
|
import com.minelittlepony.unicopia.spell.CasterUtils;
|
||||||
import com.minelittlepony.unicopia.spell.IAligned;
|
import com.minelittlepony.unicopia.spell.IAligned;
|
||||||
import com.minelittlepony.unicopia.spell.ICaster;
|
import com.minelittlepony.unicopia.spell.ICaster;
|
||||||
|
@ -82,12 +83,10 @@ public class ItemMagicStaff extends ItemStaff implements IAligned, ITossableItem
|
||||||
if (attacker.isSneaking()) {
|
if (attacker.isSneaking()) {
|
||||||
stack.damageItem(50, attacker);
|
stack.damageItem(50, attacker);
|
||||||
|
|
||||||
if (attacker instanceof EntityPlayer) {
|
CasterUtils.toCaster(attacker).ifPresent(c -> c.subtractEnergyCost(4));
|
||||||
IPower.takeFromPlayer((EntityPlayer)attacker, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
onImpact(
|
onImpact(
|
||||||
CasterUtils.toCaster(target).orElseGet(() -> CasterUtils.near(target)),
|
CasterUtils.near(target),
|
||||||
target.getPosition(),
|
target.getPosition(),
|
||||||
target.getEntityWorld().getBlockState(target.getPosition())
|
target.getEntityWorld().getBlockState(target.getPosition())
|
||||||
);
|
);
|
||||||
|
@ -140,9 +139,10 @@ public class ItemMagicStaff extends ItemStaff implements IAligned, ITossableItem
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toss(World world, ItemStack stack, EntityPlayer player) {
|
public void toss(World world, ItemStack stack, EntityPlayer player) {
|
||||||
CasterUtils.toCaster(player).ifPresent(effect::toss);
|
IPlayer iplayer = PlayerSpeciesList.instance().getPlayer(player);
|
||||||
|
|
||||||
IPower.takeFromPlayer(player, 4);
|
iplayer.subtractEnergyCost(4);
|
||||||
|
effect.toss(iplayer);
|
||||||
|
|
||||||
stack.damageItem(1, player);
|
stack.damageItem(1, player);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.minelittlepony.unicopia.player;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.network.EffectSync;
|
||||||
|
import com.minelittlepony.unicopia.spell.IAligned;
|
||||||
|
import com.minelittlepony.unicopia.spell.IAttachedEffect;
|
||||||
|
import com.minelittlepony.unicopia.spell.ICaster;
|
||||||
|
import com.minelittlepony.unicopia.spell.IMagicEffect;
|
||||||
|
import com.minelittlepony.unicopia.spell.SpellAffinity;
|
||||||
|
import com.minelittlepony.unicopia.spell.SpellRegistry;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.network.datasync.DataParameter;
|
||||||
|
import net.minecraft.network.datasync.DataSerializers;
|
||||||
|
import net.minecraft.network.datasync.EntityDataManager;
|
||||||
|
|
||||||
|
public class EntityCapabilities implements IRaceContainer<EntityLivingBase>, ICaster<EntityLivingBase> {
|
||||||
|
|
||||||
|
private static final Map<Class<? extends EntityLivingBase>, DataParameter<NBTTagCompound>> EFFECT_KEYS = Maps.newHashMap();
|
||||||
|
|
||||||
|
private final DataParameter<NBTTagCompound> EFFECT;
|
||||||
|
|
||||||
|
private final EffectSync<EntityLivingBase> effectDelegate;
|
||||||
|
|
||||||
|
private EntityLivingBase entity;
|
||||||
|
|
||||||
|
EntityCapabilities(EntityLivingBase entity) {
|
||||||
|
setOwner(entity);
|
||||||
|
|
||||||
|
EFFECT = EFFECT_KEYS.computeIfAbsent(entity.getClass(), c -> {
|
||||||
|
return EntityDataManager.createKey(c, DataSerializers.COMPOUND_TAG);
|
||||||
|
});
|
||||||
|
effectDelegate = new EffectSync<>(this, EFFECT);
|
||||||
|
|
||||||
|
entity.getDataManager().register(EFFECT, new NBTTagCompound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Race getPlayerSpecies() {
|
||||||
|
return Race.HUMAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlayerSpecies(Race race) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEffect(IMagicEffect effect) {
|
||||||
|
effectDelegate.set(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends IMagicEffect> T getEffect(Class<T> type, boolean update) {
|
||||||
|
return effectDelegate.get(type, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasEffect() {
|
||||||
|
return effectDelegate.has();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeUpdate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate() {
|
||||||
|
if (hasEffect()) {
|
||||||
|
IAttachedEffect effect = getEffect(IAttachedEffect.class, true);
|
||||||
|
|
||||||
|
if (effect != null) {
|
||||||
|
if (entity.getEntityWorld().isRemote) {
|
||||||
|
effect.renderOnPerson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!effect.updateOnPerson(this)) {
|
||||||
|
setEffect(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDimensionalTravel(int destinationDimension) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwner(EntityLivingBase owner) {
|
||||||
|
entity = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityLivingBase getOwner() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentLevel() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentLevel(int level) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpellAffinity getAffinity() {
|
||||||
|
if (getOwner() instanceof IAligned) {
|
||||||
|
return ((IAligned)getOwner()).getAffinity();
|
||||||
|
}
|
||||||
|
return SpellAffinity.NEUTRAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToNBT(NBTTagCompound compound) {
|
||||||
|
IMagicEffect effect = getEffect();
|
||||||
|
|
||||||
|
if (effect != null) {
|
||||||
|
compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(effect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFromNBT(NBTTagCompound compound) {
|
||||||
|
if (compound.hasKey("effect")) {
|
||||||
|
setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraftforge.event.entity.ProjectileImpactEvent;
|
import net.minecraftforge.event.entity.ProjectileImpactEvent;
|
||||||
import net.minecraftforge.event.entity.item.ItemTossEvent;
|
import net.minecraftforge.event.entity.item.ItemTossEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
|
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
|
import net.minecraftforge.event.entity.living.LivingEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerDropsEvent;
|
import net.minecraftforge.event.entity.player.PlayerDropsEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent;
|
import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent;
|
||||||
|
@ -31,7 +31,12 @@ class Hooks {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onPlayerJump(LivingJumpEvent event) {
|
public static void onLivingUpdate(LivingEvent.LivingUpdateEvent event) {
|
||||||
|
PlayerSpeciesList.instance().getEntity(event.getEntityLiving()).onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onPlayerJump(LivingEvent.LivingJumpEvent event) {
|
||||||
if (event.getEntityLiving() instanceof EntityPlayer) {
|
if (event.getEntityLiving() instanceof EntityPlayer) {
|
||||||
if (PlayerSpeciesList.instance().getPlayer((EntityPlayer)event.getEntityLiving()).getGravity().getGravitationConstant() < 0) {
|
if (PlayerSpeciesList.instance().getPlayer((EntityPlayer)event.getEntityLiving()).getGravity().getGravitationConstant() < 0) {
|
||||||
event.getEntityLiving().motionY = -event.getEntityLiving().motionY;
|
event.getEntityLiving().motionY = -event.getEntityLiving().motionY;
|
||||||
|
|
|
@ -37,6 +37,7 @@ import net.minecraft.network.datasync.EntityDataManager;
|
||||||
import net.minecraft.network.play.server.SPacketSetPassengers;
|
import net.minecraft.network.play.server.SPacketSetPassengers;
|
||||||
import net.minecraft.potion.PotionEffect;
|
import net.minecraft.potion.PotionEffect;
|
||||||
import net.minecraft.stats.StatList;
|
import net.minecraft.stats.StatList;
|
||||||
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -310,6 +311,22 @@ class PlayerCapabilities implements IPlayer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean subtractEnergyCost(double foodSubtract) {
|
||||||
|
if (!entity.capabilities.isCreativeMode) {
|
||||||
|
int food = (int)(entity.getFoodStats().getFoodLevel() - foodSubtract);
|
||||||
|
|
||||||
|
if (food < 0) {
|
||||||
|
entity.getFoodStats().addStats(-entity.getFoodStats().getFoodLevel(), 0);
|
||||||
|
entity.attackEntityFrom(DamageSource.MAGIC, -food/2);
|
||||||
|
} else {
|
||||||
|
entity.getFoodStats().addStats((int)-foodSubtract, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity.getHealth() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean stepOnCloud() {
|
public boolean stepOnCloud() {
|
||||||
EntityPlayer player = getOwner();
|
EntityPlayer player = getOwner();
|
||||||
|
|
|
@ -7,8 +7,10 @@ import javax.annotation.Nullable;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.UConfig;
|
import com.minelittlepony.unicopia.UConfig;
|
||||||
import com.minelittlepony.unicopia.forgebullshit.FBS;
|
import com.minelittlepony.unicopia.forgebullshit.FBS;
|
||||||
|
import com.minelittlepony.unicopia.spell.ICaster;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.item.EntityItem;
|
import net.minecraft.entity.item.EntityItem;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
|
||||||
|
@ -65,6 +67,10 @@ public class PlayerSpeciesList {
|
||||||
return new ItemCapabilities();
|
return new ItemCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entity instanceof EntityLivingBase) {
|
||||||
|
return new EntityCapabilities((EntityLivingBase)entity);
|
||||||
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("entity");
|
throw new IllegalArgumentException("entity");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +88,12 @@ public class PlayerSpeciesList {
|
||||||
return getPlayer(IPlayer.getPlayerFromServer(playerId));
|
return getPlayer(IPlayer.getPlayerFromServer(playerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Nullable
|
||||||
|
public <T extends EntityLivingBase> ICaster<T> getCaster(T entity) {
|
||||||
|
return (ICaster<T>)getEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
public <T extends Entity> IRaceContainer<T> getEntity(T entity) {
|
public <T extends Entity> IRaceContainer<T> getEntity(T entity) {
|
||||||
return FBS.of(entity).getRaceContainer();
|
return FBS.of(entity).getRaceContainer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,38 +10,11 @@ import com.minelittlepony.util.shape.IShape;
|
||||||
import com.minelittlepony.util.shape.Sphere;
|
import com.minelittlepony.util.shape.Sphere;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
|
||||||
import net.minecraft.util.DamageSource;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public interface IPower<T extends IData> extends IKeyBind {
|
public interface IPower<T extends IData> extends IKeyBind {
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtracts a given food amount from the player.
|
|
||||||
* Harms the player if there is not enough hunger available.
|
|
||||||
*/
|
|
||||||
static boolean takeFromPlayer(EntityPlayer player, double foodSubtract) {
|
|
||||||
if (!player.capabilities.isCreativeMode) {
|
|
||||||
int food = (int)(player.getFoodStats().getFoodLevel() - foodSubtract);
|
|
||||||
if (food < 0) {
|
|
||||||
player.getFoodStats().addStats(-player.getFoodStats().getFoodLevel(), 0);
|
|
||||||
player.attackEntityFrom(DamageSource.MAGIC, -food/2);
|
|
||||||
} else {
|
|
||||||
player.getFoodStats().addStats((int)-foodSubtract, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return player.getHealth() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double getPlayerEyeYPos(EntityPlayer player) {
|
|
||||||
if (player.getEntityWorld().isRemote) {
|
|
||||||
return player.posY + player.getEyeHeight() - player.getYOffset();
|
|
||||||
}
|
|
||||||
return player.posY + player.getEyeHeight() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spawnParticles(int particleId, Entity entity, int count, int...args) {
|
static void spawnParticles(int particleId, Entity entity, int count, int...args) {
|
||||||
double halfDist = entity.getEyeHeight() / 1.5;
|
double halfDist = entity.getEyeHeight() / 1.5;
|
||||||
double middle = entity.getEntityBoundingBox().minY + halfDist;
|
double middle = entity.getEntityBoundingBox().minY + halfDist;
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class PowerGrow implements IPower<Location> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
IPower.takeFromPlayer(player.getOwner(), count * 5);
|
player.subtractEnergyCost(count * 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,13 +166,13 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
|
||||||
spawnParticleRing(player, i);
|
spawnParticleRing(player, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPower.takeFromPlayer(player, rad);
|
iplayer.subtractEnergyCost(rad);
|
||||||
} else if (data.hitType == 1) {
|
} else if (data.hitType == 1) {
|
||||||
|
|
||||||
boolean harmed = player.getHealth() < player.getMaxHealth();
|
boolean harmed = player.getHealth() < player.getMaxHealth();
|
||||||
|
|
||||||
if (harmed && player.world.rand.nextInt(30) == 0) {
|
if (harmed && player.world.rand.nextInt(30) == 0) {
|
||||||
IPower.takeFromPlayer(player, 3);
|
iplayer.subtractEnergyCost(3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,12 +182,12 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
|
||||||
UWorld.enqueueTask(w -> removeTree(w, data.pos()));
|
UWorld.enqueueTask(w -> removeTree(w, data.pos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
IPower.takeFromPlayer(player, 3);
|
iplayer.subtractEnergyCost(3);
|
||||||
} else {
|
} else {
|
||||||
int cost = dropApples(player.world, data.pos());
|
int cost = dropApples(player.world, data.pos());
|
||||||
|
|
||||||
if (cost > 0) {
|
if (cost > 0) {
|
||||||
IPower.takeFromPlayer(player, cost * 3);
|
iplayer.subtractEnergyCost(cost * 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ public class PowerTeleport implements IPower<Location> {
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setPositionAndUpdate(data.x + (player.posX - Math.floor(player.posX)), data.y, data.z + (player.posZ - Math.floor(player.posZ)));
|
player.setPositionAndUpdate(data.x + (player.posX - Math.floor(player.posX)), data.y, data.z + (player.posZ - Math.floor(player.posZ)));
|
||||||
IPower.takeFromPlayer(player, distance);
|
iplayer.subtractEnergyCost(distance);
|
||||||
|
|
||||||
player.fallDistance /= distance;
|
player.fallDistance /= distance;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import javax.annotation.Nullable;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.minelittlepony.unicopia.Predicates;
|
import com.minelittlepony.unicopia.Predicates;
|
||||||
import com.minelittlepony.unicopia.entity.EntitySpell;
|
import com.minelittlepony.unicopia.entity.EntitySpell;
|
||||||
|
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
@ -19,6 +20,9 @@ import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
public class CasterUtils {
|
public class CasterUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all surrounding spells withing range from the given caster.
|
||||||
|
*/
|
||||||
public static Stream<ICaster<?>> findAllSpellsInRange(ICaster<?> source, double radius) {
|
public static Stream<ICaster<?>> findAllSpellsInRange(ICaster<?> source, double radius) {
|
||||||
|
|
||||||
BlockPos origin = source.getOrigin();
|
BlockPos origin = source.getOrigin();
|
||||||
|
@ -41,6 +45,9 @@ public class CasterUtils {
|
||||||
.map(Optional::get);
|
.map(Optional::get);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all magically capabable entities in the world.
|
||||||
|
*/
|
||||||
static Stream<ICaster<?>> findAllSpells(ICaster<?> source) {
|
static Stream<ICaster<?>> findAllSpells(ICaster<?> source) {
|
||||||
return source.getWorld().getEntities(EntityLivingBase.class, e -> {
|
return source.getWorld().getEntities(EntityLivingBase.class, e -> {
|
||||||
return e instanceof ICaster || e instanceof EntityPlayer;
|
return e instanceof ICaster || e instanceof EntityPlayer;
|
||||||
|
@ -67,29 +74,50 @@ public class CasterUtils {
|
||||||
.filter(e -> !e.getDead());
|
.filter(e -> !e.getDead());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the passed in entity is holding the named effect.
|
||||||
|
* By holding that meant the effect must be attached to the caster associated with the entity.
|
||||||
|
*/
|
||||||
public static boolean isHoldingEffect(String effectName, Entity entity) {
|
public static boolean isHoldingEffect(String effectName, Entity entity) {
|
||||||
return Streams.stream(entity.getEquipmentAndArmor())
|
return Streams.stream(entity.getEquipmentAndArmor())
|
||||||
.map(SpellRegistry::getKeyFromStack)
|
.map(SpellRegistry::getKeyFromStack)
|
||||||
.anyMatch(s -> s.equals(effectName));
|
.anyMatch(s -> s.equals(effectName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new caster at the position of the given entity.
|
||||||
|
* First attempts to convert the passed entity into a caster.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
public static ICaster<?> near(@Nonnull Entity entity) {
|
public static ICaster<?> near(@Nonnull Entity entity) {
|
||||||
|
ICaster<?> result = toCasterRaw(entity);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
EntitySpell caster = new EntitySpell(entity.world);
|
EntitySpell caster = new EntitySpell(entity.world);
|
||||||
caster.copyLocationAndAnglesFrom(entity);
|
caster.copyLocationAndAnglesFrom(entity);
|
||||||
|
|
||||||
return caster;
|
return caster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to convert the passed entity into a caster using all the known methods.
|
||||||
|
*/
|
||||||
public static Optional<ICaster<?>> toCaster(@Nullable Entity entity) {
|
public static Optional<ICaster<?>> toCaster(@Nullable Entity entity) {
|
||||||
|
return Optional.ofNullable(toCasterRaw(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ICaster<?> toCasterRaw(Entity entity) {
|
||||||
if (entity instanceof ICaster<?>) {
|
if (entity instanceof ICaster<?>) {
|
||||||
return Optional.of((ICaster<?>)entity);
|
return (ICaster<?>)entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity instanceof EntityPlayer) {
|
if (entity instanceof EntityLivingBase && !(entity instanceof IMagicals)) {
|
||||||
return Optional.of(PlayerSpeciesList.instance().getPlayer((EntityPlayer)entity));
|
return PlayerSpeciesList.instance().getCaster((EntityLivingBase)entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.empty();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package com.minelittlepony.unicopia.spell;
|
package com.minelittlepony.unicopia.spell;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.player.IPlayer;
|
|
||||||
|
|
||||||
public interface IAttachedEffect extends IMagicEffect {
|
public interface IAttachedEffect extends IMagicEffect {
|
||||||
/**
|
/**
|
||||||
* Called every tick when attached to a player.
|
* Called every tick when attached to a player.
|
||||||
|
@ -9,7 +7,7 @@ public interface IAttachedEffect extends IMagicEffect {
|
||||||
* @param source The entity we are currently attached to.
|
* @param source The entity we are currently attached to.
|
||||||
* @return true to keep alive
|
* @return true to keep alive
|
||||||
*/
|
*/
|
||||||
boolean updateOnPerson(IPlayer caster);
|
boolean updateOnPerson(ICaster<?> caster);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called every tick when attached to a player. Used to apply particle effects.
|
* Called every tick when attached to a player. Used to apply particle effects.
|
||||||
|
@ -17,5 +15,5 @@ public interface IAttachedEffect extends IMagicEffect {
|
||||||
*
|
*
|
||||||
* @param source The entity we are currently attached to.
|
* @param source The entity we are currently attached to.
|
||||||
*/
|
*/
|
||||||
default void renderOnPerson(IPlayer source) {}
|
default void renderOnPerson(ICaster<?> source) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import java.util.stream.Stream;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.EntitySpell;
|
import com.minelittlepony.unicopia.entity.EntitySpell;
|
||||||
|
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||||
import com.minelittlepony.unicopia.player.IOwned;
|
import com.minelittlepony.unicopia.player.IOwned;
|
||||||
import com.minelittlepony.unicopia.power.IPower;
|
import com.minelittlepony.unicopia.power.IPower;
|
||||||
import com.minelittlepony.util.shape.IShape;
|
import com.minelittlepony.util.shape.IShape;
|
||||||
|
@ -15,28 +16,45 @@ import com.minelittlepony.util.vector.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.BlockPos;
|
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, IAligned {
|
/**
|
||||||
|
* Interface for any magically capable entities that can cast and persist spells.
|
||||||
|
*/
|
||||||
|
public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelled, IAligned, IMagicals {
|
||||||
|
|
||||||
void setEffect(@Nullable IMagicEffect effect);
|
void setEffect(@Nullable IMagicEffect effect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the active effect for this caster.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
default IMagicEffect getEffect(boolean update) {
|
default IMagicEffect getEffect(boolean update) {
|
||||||
return getEffect(null, update);
|
return getEffect(null, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the active effect for the matching given type.
|
||||||
|
* Returns null if no such effect exists for this caster.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
<T extends IMagicEffect> T getEffect(@Nullable Class<T> type, boolean update);
|
<T extends IMagicEffect> T getEffect(@Nullable Class<T> type, boolean update);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the active effect for this caster updating it if needed.
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
default IMagicEffect getEffect() {
|
default IMagicEffect getEffect() {
|
||||||
return getEffect(true);
|
return getEffect(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this caster has an active effect attached to it.
|
||||||
|
*/
|
||||||
boolean hasEffect();
|
boolean hasEffect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,6 +99,17 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
||||||
return getEntity().getPosition();
|
return getEntity().getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the center position where this caster is located.
|
||||||
|
*/
|
||||||
|
default Vec3d getOriginVector() {
|
||||||
|
return getEntity().getPositionVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new caster at the given position.
|
||||||
|
* This one is not altered, rather the method will return an entirely new caster with the same owner as this one.
|
||||||
|
*/
|
||||||
default ICaster<?> at(BlockPos newOrigin) {
|
default ICaster<?> at(BlockPos newOrigin) {
|
||||||
EntitySpell spell = new EntitySpell(getWorld());
|
EntitySpell spell = new EntitySpell(getWorld());
|
||||||
spell.setPosition(newOrigin.getX(), newOrigin.getY(), newOrigin.getZ());
|
spell.setPosition(newOrigin.getX(), newOrigin.getY(), newOrigin.getZ());
|
||||||
|
@ -89,10 +118,6 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
||||||
return spell;
|
return spell;
|
||||||
}
|
}
|
||||||
|
|
||||||
default Vec3d getOriginVector() {
|
|
||||||
return getEntity().getPositionVector();
|
|
||||||
}
|
|
||||||
|
|
||||||
default void spawnParticles(int particleId, int count, int...args) {
|
default void spawnParticles(int particleId, int count, int...args) {
|
||||||
IPower.spawnParticles(particleId, getEntity(), count, args);
|
IPower.spawnParticles(particleId, getEntity(), count, args);
|
||||||
}
|
}
|
||||||
|
@ -107,6 +132,12 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean subtractEnergyCost(double amount) {
|
||||||
|
getOwner().attackEntityFrom(DamageSource.MAGIC, (int)amount/2);
|
||||||
|
|
||||||
|
return getOwner().getHealth() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
default Stream<ICaster<?>> findAllSpells() {
|
default Stream<ICaster<?>> findAllSpells() {
|
||||||
return CasterUtils.findAllSpells(this);
|
return CasterUtils.findAllSpells(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an object with an action to perform when dispensed from a dispenser.
|
* Represents an object with an action to perform when dispensed from a dispenser.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface IDispenceable extends IMagicEffect {
|
public interface IDispenceable extends IMagicEffect {
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package com.minelittlepony.unicopia.spell;
|
package com.minelittlepony.unicopia.spell;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||||
import com.minelittlepony.unicopia.init.UBlocks;
|
import com.minelittlepony.unicopia.init.UBlocks;
|
||||||
import com.minelittlepony.unicopia.init.USounds;
|
import com.minelittlepony.unicopia.init.USounds;
|
||||||
import com.minelittlepony.unicopia.player.IPlayer;
|
|
||||||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||||
import com.minelittlepony.util.WorldEvent;
|
import com.minelittlepony.util.WorldEvent;
|
||||||
|
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.init.Items;
|
import net.minecraft.init.Items;
|
||||||
|
@ -51,9 +52,14 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
return new ItemStack(Items.SLIME_BALL);
|
return new ItemStack(Items.SLIME_BALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkStruggleCondition(ICaster<?> caster) {
|
||||||
|
return !caster.getOrigin().equals(previousTrappedPosition)
|
||||||
|
|| (!(caster.getOwner() instanceof EntityPlayer) && caster.getWorld().rand.nextInt(20) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateOnPerson(IPlayer caster) {
|
public boolean updateOnPerson(ICaster<?> caster) {
|
||||||
EntityPlayer entity = caster.getOwner();
|
EntityLivingBase entity = caster.getOwner();
|
||||||
|
|
||||||
if (entity.motionY > 0) {
|
if (entity.motionY > 0) {
|
||||||
entity.playSound(SoundEvents.BLOCK_SLIME_HIT, 1, 1);
|
entity.playSound(SoundEvents.BLOCK_SLIME_HIT, 1, 1);
|
||||||
|
@ -67,14 +73,12 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
setDirty(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!caster.getWorld().isRemote) {
|
if (!caster.getWorld().isRemote && checkStruggleCondition(caster)) {
|
||||||
if (!origin.equals(previousTrappedPosition)) {
|
previousTrappedPosition = origin;
|
||||||
previousTrappedPosition = origin;
|
struggleCounter--;
|
||||||
struggleCounter--;
|
WorldEvent.DESTROY_BLOCK.play(caster.getWorld(), origin, Blocks.SLIME_BLOCK.getDefaultState());
|
||||||
WorldEvent.DESTROY_BLOCK.play(caster.getWorld(), origin, Blocks.SLIME_BLOCK.getDefaultState());
|
|
||||||
|
|
||||||
setDirty(true);
|
setDirty(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caster.getWorld().isAirBlock(origin) || caster.getWorld().getBlockState(origin).getBlock().isReplaceable(caster.getWorld(), origin)) {
|
if (caster.getWorld().isAirBlock(origin) || caster.getWorld().getBlockState(origin).getBlock().isReplaceable(caster.getWorld(), origin)) {
|
||||||
|
@ -97,7 +101,10 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
entity.hurtTime = 2;
|
entity.hurtTime = 2;
|
||||||
entity.collidedHorizontally = true;
|
entity.collidedHorizontally = true;
|
||||||
entity.collided = true;
|
entity.collided = true;
|
||||||
entity.capabilities.isFlying = false;
|
|
||||||
|
if (entity instanceof EntityPlayer) {
|
||||||
|
((EntityPlayer)entity).capabilities.isFlying = false;
|
||||||
|
}
|
||||||
|
|
||||||
PotionEffect SLIME_REGEN = new PotionEffect(MobEffects.REGENERATION, 0);
|
PotionEffect SLIME_REGEN = new PotionEffect(MobEffects.REGENERATION, 0);
|
||||||
|
|
||||||
|
@ -126,7 +133,7 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderOnPerson(IPlayer source) {
|
public void renderOnPerson(ICaster<?> source) {
|
||||||
render(source);
|
render(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +147,7 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
setDirty(true);
|
setDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void entrap(IPlayer e) {
|
protected void entrap(ICaster<?> e) {
|
||||||
|
|
||||||
SpellChangelingTrap existing = e.getEffect(SpellChangelingTrap.class, true);
|
SpellChangelingTrap existing = e.getEffect(SpellChangelingTrap.class, true);
|
||||||
|
|
||||||
|
@ -155,8 +162,8 @@ public class SpellChangelingTrap extends AbstractSpell implements ITossedEffect,
|
||||||
public void onImpact(ICaster<?> caster, BlockPos pos, IBlockState state) {
|
public void onImpact(ICaster<?> caster, BlockPos pos, IBlockState state) {
|
||||||
if (caster.isLocal()) {
|
if (caster.isLocal()) {
|
||||||
caster.findAllEntitiesInRange(5)
|
caster.findAllEntitiesInRange(5)
|
||||||
.filter(e -> e instanceof EntityPlayer)
|
.filter(e -> !(e instanceof IMagicals) && e instanceof EntityLivingBase)
|
||||||
.map(e -> PlayerSpeciesList.instance().getPlayer((EntityPlayer)e))
|
.map(e -> PlayerSpeciesList.instance().getCaster((EntityLivingBase)e))
|
||||||
.forEach(this::entrap);
|
.forEach(this::entrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,8 +146,6 @@ public class SpellDisguise extends AbstractSpell implements IAttachedEffect, ISu
|
||||||
entity.setUniqueId(UUID.randomUUID());
|
entity.setUniqueId(UUID.randomUUID());
|
||||||
entity.extinguish();
|
entity.extinguish();
|
||||||
|
|
||||||
PlayerSpeciesList.instance().getPlayer((EntityPlayer)entity).setEffect(null);
|
|
||||||
|
|
||||||
onEntityLoaded(source);
|
onEntityLoaded(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +177,8 @@ public class SpellDisguise extends AbstractSpell implements IAttachedEffect, ISu
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CasterUtils.toCaster(entity).ifPresent(c -> c.setEffect(null));
|
||||||
|
|
||||||
if (source.getWorld().isRemote) {
|
if (source.getWorld().isRemote) {
|
||||||
source.getWorld().spawnEntity(entity);
|
source.getWorld().spawnEntity(entity);
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,7 @@ public class SpellDisguise extends AbstractSpell implements IAttachedEffect, ISu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateOnPerson(IPlayer caster) {
|
public boolean updateOnPerson(ICaster<?> caster) {
|
||||||
return update(caster);
|
return update(caster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import com.minelittlepony.unicopia.particle.ParticleConnection;
|
||||||
import com.minelittlepony.unicopia.particle.Particles;
|
import com.minelittlepony.unicopia.particle.Particles;
|
||||||
import com.minelittlepony.unicopia.player.IPlayer;
|
import com.minelittlepony.unicopia.player.IPlayer;
|
||||||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||||
import com.minelittlepony.unicopia.power.IPower;
|
|
||||||
import com.minelittlepony.util.ProjectileUtil;
|
import com.minelittlepony.util.ProjectileUtil;
|
||||||
import com.minelittlepony.util.shape.Sphere;
|
import com.minelittlepony.util.shape.Sphere;
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ public class SpellShield extends AbstractSpell.RangedAreaSpell implements IAttac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderOnPerson(IPlayer source) {
|
public void renderOnPerson(ICaster<?> source) {
|
||||||
render(source);
|
render(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ public class SpellShield extends AbstractSpell.RangedAreaSpell implements IAttac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateOnPerson(IPlayer source) {
|
public boolean updateOnPerson(ICaster<?> source) {
|
||||||
int costMultiplier = applyEntities(source);
|
int costMultiplier = applyEntities(source);
|
||||||
if (costMultiplier > 0) {
|
if (costMultiplier > 0) {
|
||||||
if (source.getOwner().ticksExisted % 20 == 0) {
|
if (source.getOwner().ticksExisted % 20 == 0) {
|
||||||
|
@ -66,7 +65,7 @@ public class SpellShield extends AbstractSpell.RangedAreaSpell implements IAttac
|
||||||
cost *= costMultiplier / 5F;
|
cost *= costMultiplier / 5F;
|
||||||
System.out.println("Taking " + cost);
|
System.out.println("Taking " + cost);
|
||||||
|
|
||||||
if (!IPower.takeFromPlayer(source.getOwner(), cost)) {
|
if (!source.subtractEnergyCost(cost)) {
|
||||||
setDead();
|
setDead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue