164 lines
6.7 KiB
Java
164 lines
6.7 KiB
Java
package electroblob.wizardry.spell;
|
|
|
|
import electroblob.wizardry.Wizardry;
|
|
import electroblob.wizardry.data.WizardData;
|
|
import electroblob.wizardry.event.ResurrectionEvent;
|
|
import electroblob.wizardry.item.ISpellCastingItem;
|
|
import electroblob.wizardry.item.SpellActions;
|
|
import electroblob.wizardry.packet.PacketResurrection;
|
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
|
import electroblob.wizardry.registry.Spells;
|
|
import electroblob.wizardry.registry.WizardryItems;
|
|
import electroblob.wizardry.util.ParticleBuilder;
|
|
import electroblob.wizardry.util.ParticleBuilder.Type;
|
|
import electroblob.wizardry.util.SpellModifiers;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.util.EnumHand;
|
|
import net.minecraft.util.math.MathHelper;
|
|
import net.minecraft.util.text.TextComponentTranslation;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Comparator;
|
|
|
|
@EventBusSubscriber
|
|
public class Resurrection extends Spell {
|
|
|
|
public static final String WAIT_TIME = "wait_time";
|
|
|
|
private static final String POTION_CORE_FIX_NBT_KEY = "Potion Core - Health Fix";
|
|
|
|
public Resurrection(){
|
|
super("resurrection", SpellActions.SUMMON, false);
|
|
addProperties(EFFECT_RADIUS, WAIT_TIME);
|
|
}
|
|
|
|
@Override
|
|
public boolean requiresPacket(){
|
|
return false; // Has its own packets
|
|
}
|
|
|
|
@Override
|
|
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
|
|
|
WizardData data = WizardData.get(caster);
|
|
|
|
double radius = getProperty(EFFECT_RADIUS).doubleValue() * modifiers.get(WizardryItems.range_upgrade);
|
|
|
|
if(!world.isRemote && caster.getServer() != null){
|
|
// Potency reduces the time you have to wait to resurrect an ally
|
|
int waitTime = (int)(getProperty(WAIT_TIME).floatValue() / modifiers.get(SpellModifiers.POTENCY));
|
|
|
|
EntityPlayerMP nearestDeadAlly = caster.getServer().getPlayerList().getPlayers().stream()
|
|
.filter(p -> !p.isEntityAlive() && p.deathTime > waitTime && (data.isPlayerAlly(p) || caster == p)
|
|
&& p.getDistanceSq(caster) < radius * radius)
|
|
.min(Comparator.comparingDouble(caster::getDistanceSq))
|
|
.orElse(null);
|
|
|
|
if(nearestDeadAlly != null){
|
|
|
|
if(MinecraftForge.EVENT_BUS.post(new ResurrectionEvent(nearestDeadAlly, caster))) return false;
|
|
|
|
// When the player entity dies, it is removed from world#loadedEntityList. However, it is NOT removed
|
|
// from playerEntityList (and probably a few other places) until respawn is clicked, and since that
|
|
// never happens here we need to clean up those references or the player will have duplicate entries
|
|
// in some entity lists - and weirdness will ensue!
|
|
world.removeEntity(nearestDeadAlly); // Clean up the old entity references
|
|
resurrect(nearestDeadAlly); // Reset isDead, must be before spawning the player again
|
|
world.spawnEntity(nearestDeadAlly); // Re-add the player to all the relevant entity lists
|
|
|
|
// Notify clients to reset the appropriate fields, spawn particles and play sounds
|
|
IMessage msg = new PacketResurrection.Message(nearestDeadAlly.getEntityId());
|
|
WizardryPacketHandler.net.sendToDimension(msg, caster.dimension);
|
|
|
|
if(caster == nearestDeadAlly){
|
|
caster.getServer().getPlayerList().sendMessage(new TextComponentTranslation(
|
|
"spell." + this.getRegistryName() + ".resurrect_self", caster.getDisplayName()));
|
|
}else{
|
|
caster.getServer().getPlayerList().sendMessage(new TextComponentTranslation(
|
|
"spell." + this.getRegistryName() + ".resurrect_ally", nearestDeadAlly.getDisplayName(), caster.getDisplayName()));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Sets the given player back to alive, sets their health to half-full and (on the client) spawns particles. */
|
|
public void resurrect(EntityPlayer player){
|
|
|
|
player.isDead = false;
|
|
player.setHealth(player.getMaxHealth() / 2);
|
|
// Experience doesn't normally get reset until respawn, so we need to do that here too
|
|
player.deathTime = 0;
|
|
player.experience = 0;
|
|
player.experienceLevel = 0;
|
|
player.experienceTotal = 0;
|
|
// Not sure what potion core is 'fixing' but it breaks my resurrection, so let's unfix it!
|
|
player.getEntityData().removeTag(POTION_CORE_FIX_NBT_KEY);
|
|
|
|
if(player.world.isRemote){
|
|
ParticleBuilder.spawnHealParticles(player.world, player);
|
|
this.playSound(player.world, player, 0, -1, null); // We know the modifiers parameter isn't used
|
|
}
|
|
}
|
|
|
|
public static int getRemainingWaitTime(int timeSinceDeath){
|
|
return Math.max(0, MathHelper.ceil((Spells.resurrection.getProperty(Resurrection.WAIT_TIME).floatValue() - timeSinceDeath) / 20));
|
|
}
|
|
|
|
/** Helper method for detecting if a stack can be used to cast the resurrection spell. */
|
|
public static boolean canStackResurrect(ItemStack stack, EntityPlayer player){
|
|
return stack.getItem() instanceof ISpellCastingItem
|
|
&& Arrays.asList(((ISpellCastingItem)stack.getItem()).getSpells(stack)).contains(Spells.resurrection)
|
|
&& ((ISpellCastingItem)stack.getItem()).canCast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onPlayerTickEvent(LivingUpdateEvent event){
|
|
|
|
if(event.getEntity() instanceof EntityPlayer){
|
|
|
|
EntityPlayer player = (EntityPlayer)event.getEntity();
|
|
|
|
if(player.world.isRemote && !player.isEntityAlive()){
|
|
|
|
EntityPlayer firstPersonPlayer = Wizardry.proxy.getThePlayer();
|
|
|
|
if(WizardData.get(firstPersonPlayer).isPlayerAlly(player)){
|
|
|
|
ItemStack wand = firstPersonPlayer.getHeldItemMainhand();
|
|
|
|
if(!(wand.getItem() instanceof ISpellCastingItem)){
|
|
wand = firstPersonPlayer.getHeldItemOffhand();
|
|
if(!(wand.getItem() instanceof ISpellCastingItem)) return;
|
|
}
|
|
|
|
if(((ISpellCastingItem)wand.getItem()).getCurrentSpell(wand) == Spells.resurrection){
|
|
|
|
// TODO: Find some way of getting at the modifiers before the spell is cast
|
|
int waitTime = Spells.resurrection.getProperty(WAIT_TIME).intValue();
|
|
|
|
if(player.deathTime > waitTime){
|
|
ParticleBuilder.create(Type.SPARKLE, player.world.rand, player.posX, player.posY + 0.5, player.posZ, 0.5, false)
|
|
.clr(1, 1, 0.3f).vel(0, 0.02, 0).spawn(player.world);
|
|
}else{
|
|
ParticleBuilder.create(Type.DUST, player.world.rand, player.posX, player.posY + 0.5, player.posZ, 0.5, false)
|
|
.clr(1, 1, 0.3f).vel(0, 0.02, 0).time(50).spawn(player.world);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} |