Finish implementing SpellAreaEffect and retrofit various spell classes to extend it
This commit is contained in:
@@ -2,68 +2,55 @@ package electroblob.wizardry.spell;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.entity.living.ISpellCaster;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class EmpoweringPresence extends Spell {
|
||||
public class EmpoweringPresence extends SpellAreaEffect {
|
||||
|
||||
public EmpoweringPresence(){
|
||||
super("empowering_presence", SpellActions.POINT_UP, false);
|
||||
addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
this.alwaysSucceed(true);
|
||||
this.targetAllies(true);
|
||||
addProperties(EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
List<EntityPlayer> targets = EntityUtils.getEntitiesWithinRadius(getProperty(EFFECT_RADIUS).doubleValue()
|
||||
* modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class);
|
||||
if(target instanceof EntityPlayer || target instanceof ISpellCaster){ // Only useful for spell casters
|
||||
|
||||
for(EntityPlayer target : targets){
|
||||
if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.empowerment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.empowerment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){
|
||||
|
||||
double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade);
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;
|
||||
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(0.5f, 0.4f, 0.75f).spawn(world);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticle(World world, double x, double y, double z){
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(0.5f, 0.4f, 0.75f).spawn(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTranslationKey(){
|
||||
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
|
||||
|
||||
@@ -4,65 +4,49 @@ import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FontOfMana extends Spell {
|
||||
public class FontOfMana extends SpellAreaEffect {
|
||||
|
||||
public FontOfMana(){
|
||||
super("font_of_mana", SpellActions.POINT_UP, false);
|
||||
this.soundValues(0.7f, 1.2f, 0.4f);
|
||||
addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
this.particleDensity(1.25f);
|
||||
this.targetAllies(true);
|
||||
this.alwaysSucceed(true);
|
||||
addProperties(EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
double maxRadius = getProperty(EFFECT_RADIUS).doubleValue();
|
||||
|
||||
List<EntityPlayer> targets = EntityUtils.getEntitiesWithinRadius(
|
||||
maxRadius * modifiers.get(WizardryItems.blast_upgrade),
|
||||
caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class);
|
||||
|
||||
for(EntityPlayer target : targets){
|
||||
if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
(int)(getProperty(EFFECT_STRENGTH).intValue() + (modifiers.get(SpellModifiers.POTENCY) - 1) * 2)));
|
||||
}
|
||||
if(target instanceof EntityPlayer){ // Font of mana is only useful to players
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
(int)(getProperty(EFFECT_STRENGTH).intValue() + (modifiers.get(SpellModifiers.POTENCY) - 1) * 2)));
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
for(int i = 0; i < 100 * modifiers.get(WizardryItems.blast_upgrade); i++){
|
||||
|
||||
double radius = (1 + world.rand.nextDouble() * (maxRadius - 1)) * modifiers.get(WizardryItems.blast_upgrade);
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;
|
||||
;
|
||||
float hue = world.rand.nextFloat() * 0.4f;
|
||||
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50)
|
||||
.clr(1, 1 - hue, 0.6f + hue).spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticle(World world, double x, double y, double z){
|
||||
float hue = world.rand.nextFloat() * 0.4f;
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50)
|
||||
.clr(1, 1 - hue, 0.6f + hue).spawn(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOW) // Doesn't really matter but there's no point processing it if casting is blocked
|
||||
public static void onSpellCastPreEvent(SpellCastEvent.Pre event){
|
||||
// Moved from ItemWand (quite why this wasn't done with modifiers before I don't know!)
|
||||
|
||||
@@ -8,23 +8,28 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ForestsCurse extends SpellAreaEffect {
|
||||
|
||||
public ForestsCurse(){
|
||||
super("forests_curse", SpellActions.POINT_UP);
|
||||
super("forests_curse", SpellActions.POINT_UP, false);
|
||||
this.alwaysSucceed(true);
|
||||
this.soundValues(1, 1.1f, 0.2f);
|
||||
addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void affectEntity(World world, EntityLivingBase caster, EntityLivingBase target, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(!MagicDamage.isEntityImmune(DamageType.POISON, target) && EntityUtils.isLiving(target)){
|
||||
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
DamageSource source = caster != null ? MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON) : DamageSource.MAGIC;
|
||||
target.attackEntityFrom(source, getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade));
|
||||
@@ -34,6 +39,8 @@ public class ForestsCurse extends SpellAreaEffect {
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, amplifier));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, amplifier));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,47 +1,41 @@
|
||||
package electroblob.wizardry.spell;
|
||||
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class GroupHeal extends Spell {
|
||||
public class GroupHeal extends SpellAreaEffect {
|
||||
|
||||
public GroupHeal(){
|
||||
super("group_heal", SpellActions.POINT_UP, false);
|
||||
this.soundValues(0.7f, 1.2f, 0.4f);
|
||||
addProperties(EFFECT_RADIUS, HEALTH);
|
||||
this.targetAllies(true);
|
||||
addProperties(HEALTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
boolean flag = false;
|
||||
if(target.getHealth() < target.getMaxHealth() && target.getHealth() > 0){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(getProperty(EFFECT_RADIUS).floatValue()
|
||||
* modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world);
|
||||
Heal.heal(target, getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
if(target == caster || AllyDesignationSystem.isAllied(caster, target)){
|
||||
|
||||
if(target.getHealth() < target.getMaxHealth() && target.getHealth() > 0){
|
||||
|
||||
Heal.heal(target, getProperty(HEALTH).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
if(world.isRemote) ParticleBuilder.spawnHealParticles(world, target);
|
||||
playSound(world, target, ticksInUse, -1, modifiers);
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if(world.isRemote) ParticleBuilder.spawnHealParticles(world, target);
|
||||
playSound(world, target, ticksInUse, -1, modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
return flag;
|
||||
return false; // Only succeeds if something was healed
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
// We're spawning particles above so don't bother with this method
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.BlockUtils;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -15,55 +18,90 @@ import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class IceAge extends Spell {
|
||||
public class IceAge extends SpellAreaEffect {
|
||||
|
||||
public static final String FREEZE_DURATION = "freeze_duration";
|
||||
|
||||
public IceAge(){
|
||||
super("ice_age", SpellActions.POINT_DOWN, false);
|
||||
this.soundValues(1.5f, 1.0f, 0);
|
||||
addProperties(EFFECT_RADIUS, FREEZE_DURATION, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresPacket(){
|
||||
return false;
|
||||
this.alwaysSucceed(true);
|
||||
addProperties(FREEZE_DURATION, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
freezeNearbyBlocks(world, new Vec3d(caster.posX, caster.getEntityBoundingBox().minY, caster.posZ), caster, modifiers);
|
||||
return super.cast(world, caster, hand, ticksInUse, modifiers);
|
||||
}
|
||||
|
||||
float radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
@Override
|
||||
public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){
|
||||
freezeNearbyBlocks(world, caster.getPositionVector(), caster, modifiers);
|
||||
return super.cast(world, caster, hand, ticksInUse, target, modifiers);
|
||||
}
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world);
|
||||
@Override
|
||||
public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){
|
||||
freezeNearbyBlocks(world, new Vec3d(x, y, z), null, modifiers);
|
||||
return super.cast(world, x, y, z, direction, ticksInUse, duration, modifiers);
|
||||
}
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(AllyDesignationSystem.isValidTarget(caster, target)){
|
||||
if(!world.isRemote){
|
||||
@Override
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(target instanceof EntityLiving){
|
||||
if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target,
|
||||
(int)(getProperty(FREEZE_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){
|
||||
target.playSound(WizardrySounds.MISC_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F);
|
||||
}
|
||||
}else if(target instanceof EntityPlayer){
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
}
|
||||
}
|
||||
if(target instanceof EntityLiving){
|
||||
if(((BlockStatue)WizardryBlocks.ice_statue).convertToStatue((EntityLiving)target,
|
||||
(int)(getProperty(FREEZE_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){
|
||||
target.playSound(WizardrySounds.MISC_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F);
|
||||
}
|
||||
}else if(target instanceof EntityPlayer){
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
for(int i=0; i<100; i++){
|
||||
double speed = (world.rand.nextBoolean() ? 1 : -1) * (0.1 + 0.05 * world.rand.nextDouble());
|
||||
ParticleBuilder.create(Type.SNOW)
|
||||
.pos(origin.x, origin.y + world.rand.nextDouble() * 3, origin.z)
|
||||
.vel(0, 0, 0)
|
||||
.scale(2)
|
||||
.spin(world.rand.nextDouble() * (radius - 0.5) + 0.5, speed)
|
||||
.spawn(world);
|
||||
}
|
||||
|
||||
for(int i=0; i<60; i++){
|
||||
double speed = (world.rand.nextBoolean() ? 1 : -1) * (0.05 + 0.02 * world.rand.nextDouble());
|
||||
ParticleBuilder.create(Type.CLOUD)
|
||||
.pos(origin.x, origin.y + world.rand.nextDouble() * 2.5, origin.z)
|
||||
.clr(0xffffff)
|
||||
.spin(world.rand.nextDouble() * (radius - 1) + 0.5, speed)
|
||||
.spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
private void freezeNearbyBlocks(World world, Vec3d origin, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
if(!world.isRemote && EntityUtils.canDamageBlocks(caster, world)){
|
||||
|
||||
double radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
|
||||
for(int i = -(int)radius; i <= (int)radius; i++){
|
||||
for(int j = -(int)radius; j <= (int)radius; j++){
|
||||
|
||||
BlockPos pos = new BlockPos(caster).add(i, 0, j);
|
||||
BlockPos pos = new BlockPos(origin).add(i, 0, j);
|
||||
|
||||
Integer y = BlockUtils.getNearestSurface(world, new BlockPos(pos), EnumFacing.UP, (int)radius, true, BlockUtils.SurfaceCriteria.SOLID_LIQUID_TO_AIR);
|
||||
|
||||
@@ -71,7 +109,7 @@ public class IceAge extends Spell {
|
||||
|
||||
pos = new BlockPos(pos.getX(), y, pos.getZ());
|
||||
|
||||
double dist = caster.getDistance(caster.posX + i, y, caster.posZ + j);
|
||||
double dist = origin.distanceTo(new Vec3d(origin.x + i, y, origin.z + j));
|
||||
|
||||
// Randomised with weighting so that the nearer the block the more likely it is to be snowed.
|
||||
if(y != -1 && world.rand.nextInt((int)(dist * 2) + 1) < radius && dist < radius){
|
||||
@@ -81,31 +119,6 @@ public class IceAge extends Spell {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
for(int i=0; i<100; i++){
|
||||
double speed = (world.rand.nextBoolean() ? 1 : -1) * (0.1 + 0.05 * world.rand.nextDouble());
|
||||
ParticleBuilder.create(Type.SNOW)
|
||||
.pos(caster.posX, caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 3, caster.posZ)
|
||||
.vel(0, 0, 0)
|
||||
.scale(2)
|
||||
.spin(world.rand.nextDouble() * (radius - 0.5) + 0.5, speed)
|
||||
.spawn(world);
|
||||
}
|
||||
|
||||
for(int i=0; i<60; i++){
|
||||
double speed = (world.rand.nextBoolean() ? 1 : -1) * (0.05 + 0.02 * world.rand.nextDouble());
|
||||
ParticleBuilder.create(Type.CLOUD)
|
||||
.pos(caster.posX, caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2.5, caster.posZ)
|
||||
.clr(0xffffff)
|
||||
.spin(world.rand.nextDouble() * (radius - 1) + 0.5, speed)
|
||||
.spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,21 +11,20 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityCreature;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.ai.RandomPositionGenerator;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.pathfinding.PathPoint;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class Intimidate extends Spell {
|
||||
public class Intimidate extends SpellAreaEffect {
|
||||
|
||||
/** The NBT tag name for storing the feared entity's UUID in the target's tag compound. */
|
||||
public static final String NBT_KEY = "fearedEntity";
|
||||
@@ -37,44 +36,46 @@ public class Intimidate extends Spell {
|
||||
|
||||
public Intimidate(){
|
||||
super("intimidate", SpellActions.SUMMON, false);
|
||||
addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
this.alwaysSucceed(true);
|
||||
addProperties(EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
public boolean canBeCastBy(TileEntityDispenser dispenser){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!world.isRemote){
|
||||
@Override
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
List<EntityCreature> entities = EntityUtils.getEntitiesWithinRadius(
|
||||
getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.range_upgrade),
|
||||
caster.posX, caster.posY, caster.posZ, world, EntityCreature.class);
|
||||
if(caster != null && target instanceof EntityCreature){
|
||||
|
||||
for(EntityCreature target : entities){
|
||||
// Why do we need this here?
|
||||
//runAway(target, caster);
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID());
|
||||
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID());
|
||||
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.fear,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
|
||||
}else{
|
||||
for(int i = 0; i < 30; i++){
|
||||
double x = caster.posX - 1 + world.rand.nextDouble() * 2;
|
||||
double y = caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5;
|
||||
double z = caster.posZ - 1 + world.rand.nextDouble() * 2;
|
||||
ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.9f, 0.1f, 0).spawn(world);
|
||||
}
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.fear,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
if(caster != null) origin = caster.getPositionEyes(0);
|
||||
|
||||
for(int i = 0; i < 30; i++){
|
||||
double x = origin.x - 1 + world.rand.nextDouble() * 2;
|
||||
double y = origin.y - 0.25 + world.rand.nextDouble() * 0.5;
|
||||
double z = origin.z - 1 + world.rand.nextDouble() * 2;
|
||||
ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.9f, 0.1f, 0).spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a random position away from the caster and sets the given target's AI path to that location. Defined here
|
||||
* so it can be used both in the spell itself and in the potion effect (event handler).
|
||||
|
||||
@@ -3,63 +3,44 @@ package electroblob.wizardry.spell;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class InvigoratingPresence extends Spell {
|
||||
public class InvigoratingPresence extends SpellAreaEffect {
|
||||
|
||||
public InvigoratingPresence(){
|
||||
super("invigorating_presence", SpellActions.POINT_UP, false);
|
||||
this.soundValues(0.7f, 1.2f, 0.4f);
|
||||
addProperties(EFFECT_RADIUS, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
this.alwaysSucceed(true);
|
||||
this.targetAllies(true);
|
||||
addProperties(EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
List<EntityPlayer> targets = EntityUtils.getEntitiesWithinRadius(
|
||||
getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade),
|
||||
caster.posX, caster.posY, caster.posZ, world, EntityPlayer.class);
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
for(EntityPlayer target : targets){
|
||||
if(AllyDesignationSystem.isPlayerAlly(caster, target) || target == caster){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
for(int i = 0; i < 50 * modifiers.get(WizardryItems.blast_upgrade); i++){
|
||||
|
||||
double radius = (1 + world.rand.nextDouble() * 4) * modifiers.get(WizardryItems.blast_upgrade);
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;;
|
||||
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(1, 0.2f, 0.2f).spawn(world);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticle(World world, double x, double y, double z){
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(1, 0.2f, 0.2f).spawn(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTranslationKey(){
|
||||
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
|
||||
|
||||
@@ -2,82 +2,75 @@ package electroblob.wizardry.spell;
|
||||
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlagueOfDarkness extends Spell {
|
||||
public class PlagueOfDarkness extends SpellAreaEffect {
|
||||
|
||||
public PlagueOfDarkness(){
|
||||
super("plague_of_darkness", SpellActions.POINT_DOWN, false);
|
||||
addProperties(EFFECT_RADIUS, DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
this.alwaysSucceed(true);
|
||||
addProperties(DAMAGE, EFFECT_DURATION, EFFECT_STRENGTH);
|
||||
soundValues(1, 1.1f, 0.2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
double radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(AllyDesignationSystem.isValidTarget(caster, target)
|
||||
&& !MagicDamage.isEntityImmune(DamageType.WITHER, target)){
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
if(!MagicDamage.isEntityImmune(DamageType.WITHER, target)){
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
double particleX, particleZ;
|
||||
|
||||
for(int i = 0; i < 40 * modifiers.get(WizardryItems.blast_upgrade); i++){
|
||||
|
||||
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
ParticleBuilder.create(Type.DARK_MAGIC).pos(particleX, caster.getEntityBoundingBox().minY, particleZ)
|
||||
.vel(particleX - caster.posX, 0, particleZ - caster.posZ).clr(0.1f, 0, 0).spawn(world);
|
||||
|
||||
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ)
|
||||
.vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.1f, 0, 0.05f).spawn(world);
|
||||
|
||||
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
IBlockState block = BlockUtils.getBlockEntityIsStandingOn(caster);
|
||||
|
||||
if(block != null){
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY,
|
||||
particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, Block.getStateId(block));
|
||||
}
|
||||
}
|
||||
|
||||
ParticleBuilder.create(Type.SPHERE)
|
||||
.pos(caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ)
|
||||
.scale((float)radius * 0.8f)
|
||||
.clr(0.8f, 0, 0.05f)
|
||||
.spawn(world);
|
||||
}
|
||||
|
||||
this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
double particleX, particleZ;
|
||||
|
||||
for(int i = 0; i < 40 * modifiers.get(WizardryItems.blast_upgrade); i++){
|
||||
|
||||
particleX = origin.x - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = origin.z - 1.0d + 2 * world.rand.nextDouble();
|
||||
ParticleBuilder.create(Type.DARK_MAGIC).pos(particleX, origin.y, particleZ)
|
||||
.vel(particleX - origin.x, 0, particleZ - origin.z).clr(0.1f, 0, 0).spawn(world);
|
||||
|
||||
particleX = origin.x - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = origin.z - 1.0d + 2 * world.rand.nextDouble();
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(particleX, origin.y, particleZ)
|
||||
.vel(particleX - origin.x, 0, particleZ - origin.z).time(30).clr(0.1f, 0, 0.05f).spawn(world);
|
||||
|
||||
particleX = origin.x - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = origin.z - 1.0d + 2 * world.rand.nextDouble();
|
||||
|
||||
IBlockState block = world.getBlockState(new BlockPos(origin.x, origin.y - 0.5, origin.z));
|
||||
|
||||
if(block != null){
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, origin.y,
|
||||
particleZ, particleX - origin.x, 0, particleZ - origin.z, Block.getStateId(block));
|
||||
}
|
||||
}
|
||||
|
||||
ParticleBuilder.create(Type.SPHERE).pos(origin.add(0, 0.1, 0)).scale((float)radius * 0.8f).clr(0.8f, 0, 0.05f).spawn(world);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,23 +4,27 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.play.server.SPacketEntityVelocity;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Shockwave extends Spell {
|
||||
public class Shockwave extends SpellAreaEffect {
|
||||
|
||||
public static final String MAX_REPULSION_VELOCITY = "max_repulsion_velocity";
|
||||
/** The radius within which maximum damage is dealt and maximum repulsion velocity is applied. */
|
||||
@@ -29,104 +33,83 @@ public class Shockwave extends Spell {
|
||||
public Shockwave(){
|
||||
super("shockwave", SpellActions.POINT_DOWN, false);
|
||||
this.soundValues(2, 0.5f, 0);
|
||||
addProperties(BLAST_RADIUS, DAMAGE, MAX_REPULSION_VELOCITY);
|
||||
addProperties(DAMAGE, MAX_REPULSION_VELOCITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
double radius = getProperty(BLAST_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
float radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(radius, caster.posX, caster.posY, caster.posZ, world);
|
||||
if(target instanceof EntityPlayer){
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(!Wizardry.settings.playersMoveEachOther) return false;
|
||||
|
||||
if(target instanceof EntityPlayer){
|
||||
|
||||
Wizardry.proxy.shakeScreen((EntityPlayer)target, 10);
|
||||
|
||||
if(!Wizardry.settings.playersMoveEachOther) continue;
|
||||
|
||||
if(ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring)){
|
||||
if(!world.isRemote) caster.sendStatusMessage(new TextComponentTranslation("spell.resist",
|
||||
target.getName(), this.getNameForTranslationFormatted()), true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(AllyDesignationSystem.isValidTarget(caster, target)){
|
||||
|
||||
// Produces a linear profile from 0 at the edge of the radius to 1 at the epicentre radius, then
|
||||
// a constant value of 1 within the epicentre radius.
|
||||
float proximity = (float)(1 - (Math.max(target.getDistance(caster) - EPICENTRE_RADIUS, 0))/(radius - EPICENTRE_RADIUS));
|
||||
|
||||
// Damage increases closer to player up to a maximum of 4 hearts (at 1 block distance).
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST),
|
||||
getProperty(DAMAGE).floatValue() * proximity * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
if(!world.isRemote){
|
||||
|
||||
// Entity speed increases closer to the player to a maximum of 3 (at 1 block distance).
|
||||
// This is the entity's speed compared to its distance from the player. Used for a similar triangles
|
||||
// based x, y and z speed calculation.
|
||||
double velocityFactor = proximity * getProperty(MAX_REPULSION_VELOCITY).floatValue();
|
||||
|
||||
double dx = target.posX - caster.posX;
|
||||
double dy = target.getEntityBoundingBox().minY + 1 - caster.posY;
|
||||
double dz = target.posZ - caster.posZ;
|
||||
|
||||
target.motionX = velocityFactor * dx;
|
||||
target.motionY = velocityFactor * dy;
|
||||
target.motionZ = velocityFactor * dz;
|
||||
|
||||
// Player motion is handled on that player's client so needs packets
|
||||
if(target instanceof EntityPlayerMP){
|
||||
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
||||
}
|
||||
}
|
||||
if(ItemArtefact.isArtefactActive((EntityPlayer)target, WizardryItems.amulet_anchoring)){
|
||||
if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage(
|
||||
new TextComponentTranslation("spell.resist", target.getName(),
|
||||
this.getNameForTranslationFormatted()), true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
double particleX, particleZ;
|
||||
|
||||
for(int i = 0; i < 40; i++){
|
||||
// Produces a linear profile from 0 at the edge of the radius to 1 at the epicentre radius, then
|
||||
// a constant value of 1 within the epicentre radius.
|
||||
float proximity = (float)(1 - (Math.max(origin.distanceTo(target.getPositionVector()) - EPICENTRE_RADIUS, 0))/(radius - EPICENTRE_RADIUS));
|
||||
|
||||
// particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
// particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
// ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ)
|
||||
// .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.8f, 0.8f, 1).spawn(world);
|
||||
//
|
||||
// particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
// particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
// ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ)
|
||||
// .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.9f, 0.9f, 0.9f).spawn(world);
|
||||
// Damage increases closer to player up to a maximum of 4 hearts (at 1 block distance).
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.BLAST),
|
||||
getProperty(DAMAGE).floatValue() * proximity * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
|
||||
IBlockState block = BlockUtils.getBlockEntityIsStandingOn(caster);
|
||||
if(!world.isRemote){
|
||||
|
||||
if(block != null){
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY,
|
||||
particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, Block.getStateId(block));
|
||||
}
|
||||
// Entity speed increases closer to the player to a maximum of 3 (at 1 block distance).
|
||||
// This is the entity's speed compared to its distance from the player. Used for a similar triangles
|
||||
// based x, y and z speed calculation.
|
||||
double velocityFactor = proximity * getProperty(MAX_REPULSION_VELOCITY).floatValue();
|
||||
|
||||
double dx = target.posX - origin.x;
|
||||
double dy = target.getEntityBoundingBox().minY + 1 - origin.y;
|
||||
double dz = target.posZ - origin.z;
|
||||
|
||||
target.motionX = velocityFactor * dx;
|
||||
target.motionY = velocityFactor * dy;
|
||||
target.motionZ = velocityFactor * dz;
|
||||
|
||||
// Player motion is handled on that player's client so needs packets
|
||||
if(target instanceof EntityPlayerMP){
|
||||
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
||||
}
|
||||
|
||||
ParticleBuilder.create(Type.SPHERE)
|
||||
.pos(caster.posX, caster.getEntityBoundingBox().minY + 0.1, caster.posZ)
|
||||
.scale((float)radius * 0.8f)
|
||||
.clr(0.8f, 0.9f, 1)
|
||||
.spawn(world);
|
||||
|
||||
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX,
|
||||
caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
caster.swingArm(hand);
|
||||
playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
// Can't put this in affectEntity(...) because it's only called for non-allies, plus here is client-side already
|
||||
EntityUtils.getEntitiesWithinRadius(radius, origin.x, origin.y, origin.z, world, EntityPlayer.class)
|
||||
.forEach(p -> Wizardry.proxy.shakeScreen(p, 10));
|
||||
|
||||
double particleX, particleZ;
|
||||
|
||||
for(int i = 0; i < 40; i++){
|
||||
|
||||
particleX = origin.x - 1.0d + 2 * world.rand.nextDouble();
|
||||
particleZ = origin.z - 1.0d + 2 * world.rand.nextDouble();
|
||||
|
||||
IBlockState block = world.getBlockState(new BlockPos(origin.x, origin.y - 0.5, origin.z));
|
||||
|
||||
if(block != null){
|
||||
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, origin.y,
|
||||
particleZ, particleX - origin.x, 0, particleZ - origin.z, Block.getStateId(block));
|
||||
}
|
||||
}
|
||||
|
||||
ParticleBuilder.create(Type.SPHERE).pos(origin.add(0, 0.1, 0)).scale((float)radius * 0.8f).clr(0.8f, 0.9f, 1).spawn(world);
|
||||
|
||||
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, origin.x, origin.y + 0.1, origin.z, 0, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,33 +5,88 @@ import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.AllyDesignationSystem;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/** [NYI] */
|
||||
/**
|
||||
* Generic superclass for all spells which affect entities in a radius around the caster. This allows all
|
||||
* the relevant code to be centralised. This class differs from most other spell superclasses in that it is abstract
|
||||
* and as such must be subclassed to define what the spell actually does. This is because spells of this kind do a wider
|
||||
* variety of different things, so it does not make sense to define more specific functions in this class since they
|
||||
* would be redundant in the majority of cases.
|
||||
* <p></p>
|
||||
* <i>N.B. The abstract methods in this class have a {@link Nullable} caster parameter (the caster is null when the
|
||||
* spell is cast by a dispenser). When implementing this method, be sure to check whether the caster is {@code null}
|
||||
* and deal with it appropriately.</i>
|
||||
* <p></p>
|
||||
* Properties added by this type of spell: {@link Spell#EFFECT_RADIUS}
|
||||
* <p></p>
|
||||
* By default, this type of spell can be cast by NPCs. {@link Spell#canBeCastBy(EntityLiving, boolean)}
|
||||
* <p></p>
|
||||
* By default, this type of spell can be cast by dispensers. {@link Spell#canBeCastBy(TileEntityDispenser)}
|
||||
* <p></p>
|
||||
* By default, this type of spell requires a packet to be sent. {@link Spell#requiresPacket()}
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.3
|
||||
*/
|
||||
public abstract class SpellAreaEffect extends Spell {
|
||||
|
||||
// TODO: This class doesn't really work as it is right now, it needs rethinking. The aim is to try and have all the
|
||||
// different casting methods call a single (abstract) positional method to do the actual AoE.
|
||||
|
||||
/** True if this spell should target allies of the caster instead of hostiles. Positional casting always targets
|
||||
* everything, regardless of this setting. */
|
||||
protected boolean targetAllies = false;
|
||||
/** True if this spell should succeed even if no entities are affected, false if at least one entity must be affected. */
|
||||
protected boolean alwaysSucceed = false;
|
||||
/** The average number of particles to spawn per block in this spell's area of effect. */
|
||||
protected float particleDensity = 0.65f;
|
||||
|
||||
public SpellAreaEffect(String name, EnumAction action){
|
||||
this(Wizardry.MODID, name, action);
|
||||
public SpellAreaEffect(String name, EnumAction action, boolean continuous){
|
||||
this(Wizardry.MODID, name, action, continuous);
|
||||
}
|
||||
|
||||
public SpellAreaEffect(String modID, String name, EnumAction action){
|
||||
super(modID, name, action, false);
|
||||
public SpellAreaEffect(String modID, String name, EnumAction action, boolean continuous){
|
||||
super(modID, name, action, continuous);
|
||||
this.addProperties(EFFECT_RADIUS);
|
||||
this.npcSelector((e, o) -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this spell should target allies of the caster instead of hostiles. Positional casting always targets
|
||||
* everything, regardless of this setting.
|
||||
* @param targetAllies True to call {@link SpellAreaEffect#affectEntity(World, Vec3d, EntityLivingBase, EntityLivingBase, int, int, SpellModifiers)}
|
||||
* on allies of the caster, false to call it on entities considered hostile to the caster (not
|
||||
* necessarily <i>collectively-exhaustive</i>; some entities may belong to neither category).
|
||||
* @return The spell instance, allowing this method to be chained onto the constructor.
|
||||
*/
|
||||
public SpellAreaEffect targetAllies(boolean targetAllies) {
|
||||
this.targetAllies = targetAllies;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this spell this spell should succeed even if no entities are affected.
|
||||
* @param alwaysSucceed True if this spell should succeed even if no entities are affected, false if
|
||||
* {@link SpellAreaEffect#affectEntity(World, Vec3d, EntityLivingBase, EntityLivingBase, int, int, SpellModifiers)}
|
||||
* must return true at least once for the spell to succeed
|
||||
* @return The spell instance, allowing this method to be chained onto the constructor.
|
||||
*/
|
||||
public SpellAreaEffect alwaysSucceed(boolean alwaysSucceed) {
|
||||
this.alwaysSucceed = alwaysSucceed;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of particles to spawn per block for this spell.
|
||||
* @param particleDensity The average number of particles to spawn per block in this spell's area of effect.
|
||||
@@ -43,56 +98,92 @@ public abstract class SpellAreaEffect extends Spell {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getEntitiesWithinRadius(getProperty(EFFECT_RADIUS).floatValue()
|
||||
* modifiers.get(WizardryItems.blast_upgrade), caster.posX, caster.posY, caster.posZ, world);
|
||||
|
||||
targets.removeIf(target -> !AllyDesignationSystem.isValidTarget(caster, target));
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
affectEntity(world, caster, target, modifiers);
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
spawnParticleEffect(world, caster, modifiers);
|
||||
}
|
||||
|
||||
this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
public boolean canBeCastBy(TileEntityDispenser dispenser){
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
boolean result = findAndAffectEntities(world, new Vec3d(caster.posX, caster.getEntityBoundingBox().minY, caster.posZ),
|
||||
caster, ticksInUse, modifiers);
|
||||
if(result) this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){
|
||||
boolean result = findAndAffectEntities(world, caster.getPositionVector(), caster, ticksInUse, modifiers);
|
||||
if(result) this.playSound(world, caster, ticksInUse, -1, modifiers);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cast(World world, double x, double y, double z, EnumFacing direction, int ticksInUse, int duration, SpellModifiers modifiers){
|
||||
boolean result = findAndAffectEntities(world, new Vec3d(x, y, z), null, ticksInUse, modifiers);
|
||||
if(result) this.playSound(world, x, y, z, ticksInUse, -1, modifiers);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Takes care of the shared stuff for the three casting methods. This is mainly for internal use. */
|
||||
protected boolean findAndAffectEntities(World world, Vec3d origin, @Nullable EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
double radius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(radius, origin.x, origin.y, origin.z, world);
|
||||
|
||||
if(targetAllies){
|
||||
targets.removeIf(target -> target != caster && !AllyDesignationSystem.isAllied(caster, target));
|
||||
}else{
|
||||
targets.removeIf(target -> !AllyDesignationSystem.isValidTarget(caster, target));
|
||||
}
|
||||
|
||||
// Sort by distance from the origin for consistency in ordering for spells with a limit
|
||||
targets.sort(Comparator.comparingDouble(e -> e.getDistanceSq(origin.x, origin.y, origin.z)));
|
||||
|
||||
boolean result = alwaysSucceed;
|
||||
int i = 0;
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(affectEntity(world, origin, caster, target, i++, ticksInUse, modifiers)) result = true;
|
||||
}
|
||||
|
||||
if(world.isRemote) spawnParticleEffect(world, origin, radius, caster, modifiers);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to do something to each entity within the spell's area of effect.
|
||||
* @param world The world in which the spell was cast.
|
||||
* @param caster The entity that cast the spell.
|
||||
* @param origin The position the spell was cast from.
|
||||
* @param caster The entity that cast the spell, or null if it was cast from a position.
|
||||
* @param target The entity to do something to.
|
||||
* @param targetCount The number of targets that have already been affected, useful for spells with a target limit.
|
||||
* Targets will be called in order of distance from the caster/origin,
|
||||
* @param ticksInUse The number of ticks the spell has already been cast for.
|
||||
* @param modifiers The modifiers the spell was cast with.
|
||||
* @return True if whatever was done to the entity was successful, false if not.
|
||||
*/
|
||||
protected abstract void affectEntity(World world, EntityLivingBase caster, EntityLivingBase target, SpellModifiers modifiers);
|
||||
protected abstract boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers);
|
||||
|
||||
/**
|
||||
* Called to spawn the spell's particle effect. By default, this generates a set of random points within the spell's
|
||||
* area of effect and calls {@link SpellAreaEffect#spawnParticle(World, double, double, double)} at each to spawn
|
||||
* the individual particles. Only called client-side. Override to add a custom particle effect.
|
||||
* @param world The world to spawn the particles in.
|
||||
* @param caster The caster of the spell.
|
||||
* @param origin The position the spell was cast from.
|
||||
* @param radius The radius around the origin that was affected by this spell.
|
||||
* @param caster The entity that cast the spell, or null if it was cast from a position.
|
||||
* @param modifiers The modifiers the spell was cast with.
|
||||
*/
|
||||
protected void spawnParticleEffect(World world, EntityLivingBase caster, SpellModifiers modifiers){
|
||||
*/
|
||||
protected void spawnParticleEffect(World world, Vec3d origin, double radius, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
|
||||
|
||||
double maxRadius = getProperty(EFFECT_RADIUS).floatValue() * modifiers.get(WizardryItems.blast_upgrade);
|
||||
int particleCount = (int)Math.round(particleDensity * Math.PI * maxRadius * maxRadius);
|
||||
int particleCount = (int)Math.round(particleDensity * Math.PI * radius * radius);
|
||||
|
||||
for(int i=0; i<particleCount; i++){
|
||||
|
||||
double radius = (1 + world.rand.nextDouble() * (maxRadius - 1));
|
||||
double r = (1 + world.rand.nextDouble() * (radius - 1));
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2f;
|
||||
|
||||
spawnParticle(world, caster.posX + radius * MathHelper.cos(angle),
|
||||
caster.getEntityBoundingBox().minY,
|
||||
caster.posZ + radius * MathHelper.sin(angle));
|
||||
spawnParticle(world, origin.x + r * MathHelper.cos(angle), origin.y, origin.z + r * MathHelper.sin(angle));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user