Initial 1.11.2 update
This commit is contained in:
@@ -8,12 +8,15 @@ import net.minecraftforge.event.entity.living.LivingAttackEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
/** This interface allows {@link MagicDamage} and {@link IndirectMagicDamage} to both be treated as instances of a
|
||||
* single type so that the damage type field can be accessed, rather than having to deal with each of them separately,
|
||||
* which would be inefficient and cumbersome (the latter of those classes cannot extend the former because they both
|
||||
* need to extend different subclasses of {@link net.minecraft.util.DamageSource DamageSource}).
|
||||
/**
|
||||
* This interface allows {@link MagicDamage} and {@link IndirectMagicDamage} to both be treated as instances of a single
|
||||
* type so that the damage type field can be accessed, rather than having to deal with each of them separately, which
|
||||
* would be inefficient and cumbersome (the latter of those classes cannot extend the former because they both need to
|
||||
* extend different subclasses of {@link net.minecraft.util.DamageSource DamageSource}).
|
||||
*
|
||||
* @since Wizardry 1.1
|
||||
* @author Electroblob */
|
||||
* @author Electroblob
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public interface IElementalDamage {
|
||||
|
||||
@@ -33,7 +36,8 @@ public interface IElementalDamage {
|
||||
// One convenient side effect of the new damage type system is that I can get rid of all the places where
|
||||
// creepers are charged and just put them here under shock damage - this is precisely the sort of
|
||||
// repetitive code I was trying to get rid of, since errors can (and did!) occur.
|
||||
if(event.getEntityLiving() instanceof EntityCreeper && !((EntityCreeper)event.getEntityLiving()).getPowered()
|
||||
if(event.getEntityLiving() instanceof EntityCreeper
|
||||
&& !((EntityCreeper)event.getEntityLiving()).getPowered()
|
||||
&& ((IElementalDamage)event.getSource()).getType() == DamageType.SHOCK){
|
||||
// Charges creepers when they are hit by shock damage
|
||||
WizardryUtilities.chargeCreeper((EntityCreeper)event.getEntityLiving());
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.EntityDamageSourceIndirect;
|
||||
|
||||
public class IndirectMagicDamage extends EntityDamageSourceIndirect implements IElementalDamage {
|
||||
|
||||
|
||||
private final DamageType type;
|
||||
private final boolean isRetaliatory;
|
||||
|
||||
|
||||
@@ -12,24 +12,26 @@ import net.minecraft.util.text.TextComponentTranslation;
|
||||
* purpose of displaying the correct death message. <i>The event handler deals with all damage dealt by summoned
|
||||
* creatures, so it's very unlikely that this will be needed anywhere else. If for some reason it is, note that
|
||||
* knockback has to be removed and re-applied after the damage is dealt.</i>
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.2
|
||||
* @see MinionDamage
|
||||
*/
|
||||
public class IndirectMinionDamage extends IndirectMagicDamage {
|
||||
|
||||
|
||||
private Entity minion;
|
||||
|
||||
public IndirectMinionDamage(String name, Entity projectile, Entity minion, Entity caster, DamageType type, boolean isRetaliatory) {
|
||||
public IndirectMinionDamage(String name, Entity projectile, Entity minion, Entity caster, DamageType type,
|
||||
boolean isRetaliatory){
|
||||
super(name, projectile, caster, type, isRetaliatory);
|
||||
this.minion = minion;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ITextComponent getDeathMessage(EntityLivingBase victim) {
|
||||
public ITextComponent getDeathMessage(EntityLivingBase victim){
|
||||
ITextComponent itextcomponent = this.minion.getDisplayName();
|
||||
String key = "death.attack." + this.damageType;
|
||||
return new TextComponentTranslation(key, victim.getDisplayName(), itextcomponent);
|
||||
String key = "death.attack." + this.damageType;
|
||||
return new TextComponentTranslation(key, victim.getDisplayName(), itextcomponent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import net.minecraft.entity.monster.EntityPigZombie;
|
||||
import net.minecraft.entity.monster.EntitySkeleton;
|
||||
import net.minecraft.entity.monster.EntitySnowman;
|
||||
import net.minecraft.entity.monster.EntitySpider;
|
||||
import net.minecraft.entity.monster.EntityWitherSkeleton;
|
||||
import net.minecraft.entity.monster.EntityZombie;
|
||||
import net.minecraft.entity.monster.SkeletonType;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EntityDamageSource;
|
||||
|
||||
@@ -44,40 +44,47 @@ import net.minecraft.util.EntityDamageSource;
|
||||
// applied to any damagesource, but these aren't considered types in their own right; rather, they seem to be damage
|
||||
// type 'attributes'. This is my attempt to collect all of these into a reasonably coherent system.
|
||||
|
||||
/** As of wizardry 1.1, this class has replaced the damagesource-related methods in WizardryUtilities, allowing a
|
||||
* {@link DamageType} to be specified with the damage. The main reason for this is so that damage sources can fit with the
|
||||
* vanilla behaviour on armour enchantments and such like whilst still being classified as wizardry damage for the purposes
|
||||
* of friendly fire, etc.
|
||||
* <p><i>
|
||||
* In the future, there is scope for an entirely standalone mod based on this idea. Perhaps 'Elemental Damage' could be
|
||||
* a config-only mod which allows its users to define any number of specific damage types, then give any creature a
|
||||
/**
|
||||
* As of wizardry 1.1, this class has replaced the damagesource-related methods in WizardryUtilities, allowing a
|
||||
* {@link DamageType} to be specified with the damage. The main reason for this is so that damage sources can fit with
|
||||
* the vanilla behaviour on armour enchantments and such like whilst still being classified as wizardry damage for the
|
||||
* purposes of friendly fire, etc.
|
||||
* <p>
|
||||
* <i> In the future, there is scope for an entirely standalone mod based on this idea. Perhaps 'Elemental Damage' could
|
||||
* be a config-only mod which allows its users to define any number of specific damage types, then give any creature a
|
||||
* resistance, immunity or vulnerability to each, as well as being able to specify the sources for each type, such as
|
||||
* enchantments, potions, specific items, certain entities, even particular situations and string damagesource names
|
||||
* from other mods.
|
||||
* </i>
|
||||
* from other mods. </i>
|
||||
*
|
||||
* @see IndirectMagicDamage
|
||||
* @see IElementalDamage
|
||||
* @since Wizardry 1.1
|
||||
* @author Electroblob */
|
||||
* @author Electroblob
|
||||
*/
|
||||
public class MagicDamage extends EntityDamageSource implements IElementalDamage {
|
||||
|
||||
|
||||
/** The name of the damagesource for direct magic damage from the wizardry mod. */
|
||||
public static final String DIRECT_MAGIC_DAMAGE = "wizardryMagic";
|
||||
/** The name of the damagesource for indirect magic damage from the wizardry mod. */
|
||||
public static final String INDIRECT_MAGIC_DAMAGE = "indirectWizardryMagic";
|
||||
// Technically, I don't need to specify that the classes in this map must extend entity, but it's good practice to.
|
||||
private static final Map<Class<? extends Entity>, DamageType[]> immunityMapping = new HashMap<Class<? extends Entity>, DamageType[]>();
|
||||
|
||||
|
||||
private final DamageType type;
|
||||
private final boolean isRetaliatory;
|
||||
|
||||
/** A simple set of constants for the types of damage. The names are deliberately different to those in EnumElement
|
||||
* to avoid confusion. All types are classified as magic damage in the vanilla system, so witches are resistant to them. */
|
||||
|
||||
/**
|
||||
* A simple set of constants for the types of damage. The names are deliberately different to those in EnumElement
|
||||
* to avoid confusion. All types are classified as magic damage in the vanilla system, so witches are resistant to
|
||||
* them.
|
||||
*/
|
||||
public enum DamageType {
|
||||
/** Generic magic damage from the wizardry mod. Like vanilla magic damage, except it doesn't bypass armour. */
|
||||
MAGIC,
|
||||
/** Fire damage from the wizardry mod. Counts as fire damage in the vanilla system, so is blocked by any mobs that
|
||||
* are immune to fire and entities with the fire resistance effect. */
|
||||
/**
|
||||
* Fire damage from the wizardry mod. Counts as fire damage in the vanilla system, so is blocked by any mobs
|
||||
* that are immune to fire and entities with the fire resistance effect.
|
||||
*/
|
||||
FIRE,
|
||||
/** Frost (ice) damage from the wizardry mod. Snow golems, ice wraiths and ice giants are immune. */
|
||||
FROST,
|
||||
@@ -87,15 +94,17 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
|
||||
WITHER,
|
||||
/** Poison damage from the wizardry mod. Spiders, cave spiders and undead mobs are immune. */
|
||||
POISON,
|
||||
/** [NYI] Force damage from the wizardry mod. Insubstantial creatures (ghast, shadow wraith, etc.) are immune. */
|
||||
/**
|
||||
* [NYI] Force damage from the wizardry mod. Insubstantial creatures (ghast, shadow wraith, etc.) are immune.
|
||||
*/
|
||||
FORCE,
|
||||
/** Blast damage from the wizardry mod. Affected by the blast protection enchantment. */
|
||||
BLAST,
|
||||
/** [NYI] Radiant damage from the wizardry mod. */
|
||||
RADIANT;
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
static{
|
||||
// Of course, the entities that are immune to fire already are since there's a vanilla system for that, but
|
||||
// they're included here anyway for completeness and in case anyone wants to check if an entity is immune to
|
||||
// an unspecified element for reasons other than dealing damage.
|
||||
@@ -113,6 +122,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
|
||||
setEntityImmunities(EntityIceGiant.class, DamageType.FROST);
|
||||
setEntityImmunities(EntityLightningWraith.class, DamageType.SHOCK);
|
||||
setEntityImmunities(EntityShadowWraith.class, DamageType.WITHER);
|
||||
setEntityImmunities(EntityWitherSkeleton.class, DamageType.WITHER);
|
||||
setEntityImmunities(EntitySpider.class, DamageType.POISON);
|
||||
setEntityImmunities(EntitySpiderMinion.class, DamageType.POISON);
|
||||
setEntityImmunities(EntityCaveSpider.class, DamageType.POISON);
|
||||
@@ -130,35 +140,29 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
|
||||
if(type == DamageType.FIRE) this.setFireDamage();
|
||||
if(type == DamageType.BLAST) this.setExplosion();
|
||||
}
|
||||
|
||||
/** Returns true if the given entity is immune to the given damage type according to the entity immunity mappings,
|
||||
|
||||
/**
|
||||
* Returns true if the given entity is immune to the given damage type according to the entity immunity mappings,
|
||||
* false otherwise. When you want to check for resistances, check this method rather than just checking the result
|
||||
* of attackEntityFrom, since that could return false for all sorts of reasons besides immunities. However, if you
|
||||
* don't need to know whether the damage succeeded or not, there's no point in checking this method. A common use
|
||||
* of this method is to check for immunity and if so display the "[mob] resisted [spell]" chat message. See
|
||||
* {@link electroblob.wizardry.spell.Arc Arc} for a good example of this, and also of when not to use it. */
|
||||
* don't need to know whether the damage succeeded or not, there's no point in checking this method. A common use of
|
||||
* this method is to check for immunity and if so display the "[mob] resisted [spell]" chat message. See
|
||||
* {@link electroblob.wizardry.spell.Arc Arc} for a good example of this, and also of when not to use it.
|
||||
*/
|
||||
public static boolean isEntityImmune(DamageType type, Entity entity){
|
||||
// Because Mojang, in their infinite wisdom, did not make wither skeletons their own separate class (despite the
|
||||
// fact that cave spiders are), I have to test for this manually. Realistically, no mod author would be stupid
|
||||
// enough to put two entities in one class, so this should be the only time I ever have to do this.
|
||||
if(type == DamageType.WITHER && entity instanceof EntitySkeleton
|
||||
// Don't need to check EntitySkeletonMinion separately any more because it now extends EntitySkeleton.
|
||||
&& ((EntitySkeleton)entity).getSkeletonType() == SkeletonType.WITHER){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if(type == DamageType.FIRE && entity.isImmuneToFire()) return true;
|
||||
|
||||
|
||||
DamageType[] immunities = MagicDamage.immunityMapping.get(entity.getClass());
|
||||
|
||||
|
||||
return immunities != null && Arrays.asList(immunities).contains(type);
|
||||
}
|
||||
|
||||
|
||||
/** Registers the given type of entity as immune to all of the passed in damage types. */
|
||||
public static void setEntityImmunities(Class<? extends Entity> entityType, DamageType... immunities){
|
||||
immunityMapping.put(entityType, immunities);
|
||||
}
|
||||
|
||||
|
||||
/** Adds the passed in damage type to the list of damage types to which the given entity is immune. */
|
||||
public static void addEntityImmunity(Class<? extends Entity> entityType, DamageType immunity){
|
||||
List<DamageType> immunities = Arrays.asList(immunityMapping.get(entityType));
|
||||
@@ -169,45 +173,47 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
|
||||
|
||||
/**
|
||||
* Returns a DamageSource called "wizardryMagic" with the given entity as the caster. Use in preference to vanilla
|
||||
* types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.magic, it does
|
||||
* types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.MAGIC, it does
|
||||
* not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for
|
||||
* the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
|
||||
* isRetaliatory defaults to false.
|
||||
* <p>
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
|
||||
* mod just to get rid of this method and use the constructor instead.
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the
|
||||
* entire mod just to get rid of this method and use the constructor instead.
|
||||
*
|
||||
* @param caster The player or other living entity causing the damage
|
||||
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
|
||||
* reasonably affect creatures that are ususally immune to wither effects).
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them
|
||||
* might reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @return A damagesource object of type EntityDamageSource
|
||||
*/
|
||||
public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type){
|
||||
return causeDirectMagicDamage(caster, type, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a DamageSource called "wizardryMagic" with the given entity as the caster. Use in preference to vanilla
|
||||
* types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.magic, it does
|
||||
* types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.MAGIC, it does
|
||||
* not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for
|
||||
* the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
|
||||
* <p>
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
|
||||
* mod just to get rid of this method and use the constructor instead.
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the
|
||||
* entire mod just to get rid of this method and use the constructor instead.
|
||||
*
|
||||
* @param caster The player or other living entity causing the damage
|
||||
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
|
||||
* reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops
|
||||
* occurring when two entities damage each other with retaliatory effects.
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them
|
||||
* might reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops occurring
|
||||
* when two entities damage each other with retaliatory effects.
|
||||
* @return A damagesource object of type EntityDamageSource
|
||||
*/
|
||||
public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type, boolean isRetaliatory){
|
||||
return new MagicDamage(DIRECT_MAGIC_DAMAGE, caster, type, isRetaliatory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a DamageSource called "indirectWizardryMagic" with the player as the caster. Use in preference to vanilla
|
||||
* types to allow things to distinguish between magic and regular arrows/throwables. Unlike
|
||||
@@ -215,39 +221,42 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
|
||||
* record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
|
||||
* isRetaliatory defaults to false.
|
||||
* <p>
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
|
||||
* mod just to get rid of this method and use the constructor instead.
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the
|
||||
* entire mod just to get rid of this method and use the constructor instead.
|
||||
*
|
||||
* @param magic The entity that actually caused the damage
|
||||
* @param caster The player or other living entity that cast the spell originally
|
||||
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
|
||||
* reasonably affect creatures that are ususally immune to wither effects).
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them
|
||||
* might reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @return A damagesource object of type EntityDamageSourceIndirect
|
||||
*/
|
||||
public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type){
|
||||
return causeIndirectMagicDamage(magic, caster, type, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a DamageSource called "indirectWizardryMagic" with the player as the caster. Use in preference to vanilla
|
||||
* types to allow things to distinguish between magic and regular arrows/throwables. Unlike
|
||||
* DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the
|
||||
* record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
|
||||
* <p>
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
|
||||
* mod just to get rid of this method and use the constructor instead.
|
||||
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the
|
||||
* entire mod just to get rid of this method and use the constructor instead.
|
||||
*
|
||||
* @param magic The entity that actually caused the damage
|
||||
* @param caster The player or other living entity that cast the spell originally
|
||||
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
|
||||
* reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops
|
||||
* occurring when two entities damage each other with retaliatory effects.
|
||||
* {@link DamageType#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
|
||||
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them
|
||||
* might reasonably affect creatures that are ususally immune to wither effects).
|
||||
* @param isRetaliatory whether this damage source came from a retaliatory attack; prevents infinite loops occurring
|
||||
* when two entities damage each other with retaliatory effects.
|
||||
* @return A damagesource object of type EntityDamageSourceIndirect
|
||||
*/
|
||||
public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type, boolean isRetaliatory){
|
||||
public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type,
|
||||
boolean isRetaliatory){
|
||||
return new IndirectMagicDamage(INDIRECT_MAGIC_DAMAGE, magic, caster, type, isRetaliatory);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,21 +12,22 @@ import net.minecraft.util.text.TextComponentTranslation;
|
||||
* display the minion's name rather than the caster's. <i>The event handler deals with all damage dealt by summoned
|
||||
* creatures, so it's very unlikely that this will be needed anywhere else. If for some reason it is, note that
|
||||
* knockback has to be removed and re-applied after the damage is dealt.</i>
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.2
|
||||
* @see IndirectMinionDamage
|
||||
*/
|
||||
public class MinionDamage extends IndirectMagicDamage {
|
||||
|
||||
public MinionDamage(String name, Entity minion, Entity caster, DamageType type, boolean isRetaliatory) {
|
||||
public MinionDamage(String name, Entity minion, Entity caster, DamageType type, boolean isRetaliatory){
|
||||
super(name, minion, caster, type, isRetaliatory);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ITextComponent getDeathMessage(EntityLivingBase victim) {
|
||||
public ITextComponent getDeathMessage(EntityLivingBase victim){
|
||||
ITextComponent itextcomponent = this.damageSourceEntity.getDisplayName();
|
||||
String key = "death.attack." + this.damageType;
|
||||
return new TextComponentTranslation(key, victim.getDisplayName(), itextcomponent);
|
||||
String key = "death.attack." + this.damageType;
|
||||
return new TextComponentTranslation(key, victim.getDisplayName(), itextcomponent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,21 +12,22 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.fml.common.network.ByteBufUtils;
|
||||
|
||||
/**
|
||||
* Object that wraps any number of spell modifiers into one, allowing for expandability within the Spell#cast
|
||||
* methods. This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}.
|
||||
* It is possible to calculate spell modifiers from wand NBT within the cast methods, but this is cumbersome and does
|
||||
* not allow the modifiers to be sent to the client, which is sometimes necessary (for example, detonate needs to know
|
||||
* about range modifiers on the client side or the particles wouldn't show outside of the base range).
|
||||
* Object that wraps any number of spell modifiers into one, allowing for expandability within the Spell#cast methods.
|
||||
* This class is essentially a glorified {@link Map} which can be written to and read from a {@link ByteBuf}. It is
|
||||
* possible to calculate spell modifiers from wand NBT within the cast methods, but this is cumbersome and does not
|
||||
* allow the modifiers to be sent to the client, which is sometimes necessary (for example, detonate needs to know about
|
||||
* range modifiers on the client side or the particles wouldn't show outside of the base range).
|
||||
* <p>
|
||||
* Most external interaction with SpellModifiers objects will be in {@link SpellCastEvent.Pre}, where you can add additional
|
||||
* modifiers to them if desired for use with your own spells, or modify the existing ones. If you have added a wand
|
||||
* upgrade, this is <b>not</b> done automatically for you; you will have to do it yourself (for the simple reason that
|
||||
* not all wand upgrades affect spells). SpellModifiers objects are <i>mutable</i>, so you can simply change the values
|
||||
* they contain to modify the spell.
|
||||
* Most external interaction with SpellModifiers objects will be in {@link SpellCastEvent.Pre}, where you can add
|
||||
* additional modifiers to them if desired for use with your own spells, or modify the existing ones. If you have added
|
||||
* a wand upgrade, this is <b>not</b> done automatically for you; you will have to do it yourself (for the simple reason
|
||||
* that not all wand upgrades affect spells). SpellModifiers objects are <i>mutable</i>, so you can simply change the
|
||||
* values they contain to modify the spell.
|
||||
* <p>
|
||||
* To use a SpellModifiers object within the <code>Spell.cast</code> methods, simply retrieve the desired multiplier
|
||||
* using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the multiplier
|
||||
* is not from a wand upgrade.
|
||||
* using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the multiplier is
|
||||
* not from a wand upgrade.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.2
|
||||
* @see WandHelper
|
||||
@@ -36,45 +37,49 @@ import net.minecraftforge.fml.common.network.ByteBufUtils;
|
||||
// would mean they have to be registered, and part of the point of SpellModifiers is that they can be added to on the
|
||||
// fly.
|
||||
public final class SpellModifiers {
|
||||
|
||||
|
||||
/** Constant string identifier for the damage modifier. All the other modifiers in Wizardry have items. */
|
||||
public static final String DAMAGE = "damage";
|
||||
|
||||
private Map<String, Float> multiplierMap;
|
||||
private Map<String, Float> syncedMultiplierMap;
|
||||
|
||||
/** Creates an empty SpellModifiers object. All calls to <code>get(...)</code> on an empty SpellModifiers object
|
||||
* will return a value of 1. */
|
||||
|
||||
/**
|
||||
* Creates an empty SpellModifiers object. All calls to <code>get(...)</code> on an empty SpellModifiers object will
|
||||
* return a value of 1.
|
||||
*/
|
||||
public SpellModifiers(){
|
||||
multiplierMap = new HashMap<String, Float>();
|
||||
syncedMultiplierMap = new HashMap<String, Float>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given multiplier to this SpellModifiers object, using the string identifier that the given wand
|
||||
* upgrade item was registered with.
|
||||
* Adds the given multiplier to this SpellModifiers object, using the string identifier that the given wand upgrade
|
||||
* item was registered with.
|
||||
*
|
||||
* @throws IllegalArgumentException if the given item is not a registered special wand upgrade.
|
||||
* @param upgrade The upgrade item the multiplier corresponds to.
|
||||
* @param multiplier The multiplier value, with 1 being default. Usage of modifiers is up to individual spells to
|
||||
* implement.
|
||||
* implement.
|
||||
* @param needsSyncing Whether this multiplier should be synchronised with the client via packets. <i>Only set this
|
||||
* to true if particles will be spawned which need to know the value of the multiplier.</i>
|
||||
* to true if particles will be spawned which need to know the value of the multiplier.</i>
|
||||
* @return The SpellModifiers object, allowing this method to be chained onto the constructor.
|
||||
*/
|
||||
public SpellModifiers set(Item upgrade, float multiplier, boolean needsSyncing){
|
||||
this.set(WandHelper.getIdentifier(upgrade), multiplier, needsSyncing);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given multiplier to this SpellModifiers object, using the given string key. In most cases, the
|
||||
* multiplier will correspond to a wand upgrade, in which case use {@link SpellModifiers#set(Item, float, boolean)}
|
||||
* instead.
|
||||
*
|
||||
* @param key The key used to identify the multiplier.
|
||||
* @param multiplier The multiplier value, with 1 being default. Usage of modifiers is up to individual spells to
|
||||
* implement.
|
||||
* implement.
|
||||
* @param needsSyncing Whether this multiplier should be synchronised with the client via packets. <i>Only set this
|
||||
* to true if particles will be spawned which depend on the multiplier.</i>
|
||||
* to true if particles will be spawned which depend on the multiplier.</i>
|
||||
* @return The SpellModifiers object, allowing this method to be chained onto the constructor.
|
||||
*/
|
||||
public SpellModifiers set(String key, float multiplier, boolean needsSyncing){
|
||||
@@ -82,38 +87,44 @@ public final class SpellModifiers {
|
||||
if(needsSyncing) syncedMultiplierMap.put(key, multiplier);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns the multiplier corresponding to the given wand upgrade item, or 1 if no multiplier was stored.
|
||||
* @throws IllegalArgumentException if the given item is not a registered special wand upgrade. */
|
||||
|
||||
/**
|
||||
* Returns the multiplier corresponding to the given wand upgrade item, or 1 if no multiplier was stored.
|
||||
*
|
||||
* @throws IllegalArgumentException if the given item is not a registered special wand upgrade.
|
||||
*/
|
||||
public float get(Item upgrade){
|
||||
return get(WandHelper.getIdentifier(upgrade));
|
||||
}
|
||||
|
||||
/** Returns the multiplier corresponding to the given string key, or 1 if no multiplier was stored. In most cases,
|
||||
* the multiplier will correspond to a wand upgrade, in which case use {@link SpellModifiers#get(Item)}
|
||||
* instead. */
|
||||
|
||||
/**
|
||||
* Returns the multiplier corresponding to the given string key, or 1 if no multiplier was stored. In most cases,
|
||||
* the multiplier will correspond to a wand upgrade, in which case use {@link SpellModifiers#get(Item)} instead.
|
||||
*/
|
||||
public float get(String key){
|
||||
Float value = multiplierMap.get(key);
|
||||
// Must check for null before unboxing, and if it is null, return the default 1.
|
||||
return value == null ? 1 : value;
|
||||
}
|
||||
|
||||
/** Returns an unmodifiable map of the modifiers stored in this SpellModifiers object. Useful for iterating through
|
||||
* the modifiers. */
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of the modifiers stored in this SpellModifiers object. Useful for iterating through
|
||||
* the modifiers.
|
||||
*/
|
||||
public Map<String, Float> getModifiers(){
|
||||
return Collections.unmodifiableMap(this.multiplierMap);
|
||||
}
|
||||
|
||||
|
||||
/** Removes all modifiers from this SpellModifiers object, effectively resetting them all to 1. */
|
||||
public void reset(){
|
||||
this.multiplierMap.clear();
|
||||
this.syncedMultiplierMap.clear();
|
||||
}
|
||||
|
||||
|
||||
/** Reads this SpellModifiers object from the given ByteBuf. */
|
||||
public void read(ByteBuf buf){
|
||||
int entryCount = buf.readInt();
|
||||
for(int i=0; i<entryCount; i++){
|
||||
for(int i = 0; i < entryCount; i++){
|
||||
this.set(ByteBufUtils.readUTF8String(buf), buf.readFloat(), false);
|
||||
}
|
||||
}
|
||||
@@ -126,12 +137,16 @@ public final class SpellModifiers {
|
||||
buf.writeFloat(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more
|
||||
* float tags, which will be stored as modifiers under the same name as the tag. For example, the following NBT
|
||||
* tag (in command syntax) will create a SpellModifiers object with a damage modifier of 1.5 and a range modifier of
|
||||
* 2:<p><code>{damage:1.5, range:2}</code><p>
|
||||
* Note that needsSyncing is set to true for all returned modifiers. */
|
||||
|
||||
/**
|
||||
* Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more float
|
||||
* tags, which will be stored as modifiers under the same name as the tag. For example, the following NBT tag (in
|
||||
* command syntax) will create a SpellModifiers object with a damage modifier of 1.5 and a range modifier of 2:
|
||||
* <p>
|
||||
* <code>{damage:1.5, range:2}</code>
|
||||
* <p>
|
||||
* Note that needsSyncing is set to true for all returned modifiers.
|
||||
*/
|
||||
public static SpellModifiers fromNBT(NBTTagCompound nbt){
|
||||
SpellModifiers modifiers = new SpellModifiers();
|
||||
for(String key : nbt.getKeySet()){
|
||||
|
||||
@@ -11,29 +11,32 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/** Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods
|
||||
/**
|
||||
* Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods
|
||||
* which allow cleaner and more concise interaction with the wand NBT data, which is quite a complex structure. Such
|
||||
* interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to debug!
|
||||
* For example, this class allowed {@link electroblob.wizardry.item.ItemWand ItemWand} to be shortened by about 80 lines.
|
||||
* In addition, by having all the various null checks and array size checks in one place, the chance of accidental errors
|
||||
* due to forgetting to check these things is greatly reduced.
|
||||
* interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to
|
||||
* debug! For example, this class allowed {@link electroblob.wizardry.item.ItemWand ItemWand} to be shortened by about
|
||||
* 80 lines. In addition, by having all the various null checks and array size checks in one place, the chance of
|
||||
* accidental errors due to forgetting to check these things is greatly reduced.
|
||||
* <p>
|
||||
* Note that these methods contain no game logic at all; they are purely for interacting with the NBT data. Conversely,
|
||||
* you should never need to access the wand's NBT data directly when using this class, but the keys are public in the
|
||||
* unlikely case that this is necessary.
|
||||
* <p>
|
||||
* Also note that none of the methods in this class actually check that the given ItemStack contains an ItemWand; you
|
||||
* can, for example, pass in a stack of snowballs without causing problems, but that is of course pointless! However,
|
||||
* if you have your own spell casting item (which doesn't extend ItemWand), this setup means you can still use this class
|
||||
* can, for example, pass in a stack of snowballs without causing problems, but that is of course pointless! However, if
|
||||
* you have your own spell casting item (which doesn't extend ItemWand), this setup means you can still use this class
|
||||
* to manage its NBT structure.
|
||||
* <p>
|
||||
* All <b>get</b> methods in this class return some kind of default if the passed-in wand stack has no nbt data.
|
||||
* See individual method descriptions for more details.<br>
|
||||
* All <b>set</b> methods in this class create a new nbt data for the passed-in wand if it has none, before doing
|
||||
* All <b>get</b> methods in this class return some kind of default if the passed-in wand stack has no nbt data. See
|
||||
* individual method descriptions for more details.<br>
|
||||
* All <b>set</b> methods in this class create a new nbt data for the passed-in wand if it has none, before doing
|
||||
* whatever else they do.
|
||||
*
|
||||
* @see electroblob.wizardry.item.ItemWand ItemWand
|
||||
* @see electroblob.wizardry.packet.PacketControlInput PacketControlInput
|
||||
* @since Wizardry 1.1 */
|
||||
* @since Wizardry 1.1
|
||||
*/
|
||||
public final class WandHelper {
|
||||
|
||||
// NBT tag keys
|
||||
@@ -44,7 +47,7 @@ public final class WandHelper {
|
||||
|
||||
private static final HashMap<Item, String> upgradeMap = new HashMap<Item, String>();
|
||||
|
||||
static {
|
||||
static{
|
||||
upgradeMap.put(WizardryItems.condenser_upgrade, "condenser");
|
||||
upgradeMap.put(WizardryItems.storage_upgrade, "storage");
|
||||
upgradeMap.put(WizardryItems.siphon_upgrade, "siphon");
|
||||
@@ -55,9 +58,11 @@ public final class WandHelper {
|
||||
upgradeMap.put(WizardryItems.attunement_upgrade, "attunement");
|
||||
}
|
||||
|
||||
/** Returns an array containing the spells currently bound to the given wand. As of Wizardry 1.1, this array is not
|
||||
/**
|
||||
* Returns an array containing the spells currently bound to the given wand. As of Wizardry 1.1, this array is not
|
||||
* always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no spell data,
|
||||
* returns an array of length 0. */
|
||||
* returns an array of length 0.
|
||||
*/
|
||||
public static Spell[] getSpells(ItemStack wand){
|
||||
|
||||
Spell[] spells = new Spell[0];
|
||||
@@ -68,7 +73,7 @@ public final class WandHelper {
|
||||
|
||||
spells = new Spell[spellIDs.length];
|
||||
|
||||
for(int i=0; i<spellIDs.length; i++){
|
||||
for(int i = 0; i < spellIDs.length; i++){
|
||||
spells[i] = Spell.get(spellIDs[i]);
|
||||
}
|
||||
}
|
||||
@@ -76,14 +81,17 @@ public final class WandHelper {
|
||||
return spells;
|
||||
}
|
||||
|
||||
/** Binds the given array of spells to the given wand. The array can be anywhere between 5 and 8 (inclusive) in length. */
|
||||
/**
|
||||
* Binds the given array of spells to the given wand. The array can be anywhere between 5 and 8 (inclusive) in
|
||||
* length.
|
||||
*/
|
||||
public static void setSpells(ItemStack wand, Spell[] spells){
|
||||
|
||||
if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound()));
|
||||
|
||||
int[] spellIDs = new int[spells.length];
|
||||
|
||||
for(int i=0; i<spells.length; i++){
|
||||
for(int i = 0; i < spells.length; i++){
|
||||
spellIDs[i] = spells[i] != null ? spells[i].id() : Spells.none.id();
|
||||
}
|
||||
|
||||
@@ -111,12 +119,12 @@ public final class WandHelper {
|
||||
public static void selectNextSpell(ItemStack wand){
|
||||
// 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades
|
||||
if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]);
|
||||
|
||||
|
||||
if(wand.getTagCompound() != null){
|
||||
|
||||
int numberOfSpells = getSpells(wand).length;
|
||||
int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
|
||||
|
||||
|
||||
// Greater than or equal to so that if attunement upgrades are somehow removed by NBT modification it just
|
||||
// resets.
|
||||
if(selectedSpell >= numberOfSpells - 1){
|
||||
@@ -124,36 +132,38 @@ public final class WandHelper {
|
||||
}else{
|
||||
selectedSpell++;
|
||||
}
|
||||
|
||||
|
||||
wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Selects the previous spell in this wand's list of spells. */
|
||||
public static void selectPreviousSpell(ItemStack wand){
|
||||
|
||||
|
||||
// 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades
|
||||
if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]);
|
||||
// This cannot possibly be null here, and yet I am getting an NPE...
|
||||
if(wand.getTagCompound() != null){
|
||||
|
||||
|
||||
int numberOfSpells = getSpells(wand).length;
|
||||
int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
|
||||
|
||||
|
||||
if(selectedSpell <= 0){
|
||||
selectedSpell = numberOfSpells - 1;
|
||||
}else{
|
||||
selectedSpell--;
|
||||
}
|
||||
|
||||
|
||||
wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, selectedSpell);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not
|
||||
/**
|
||||
* Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not
|
||||
* always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no cooldown data,
|
||||
* returns an array of length 0. */
|
||||
* returns an array of length 0.
|
||||
*/
|
||||
public static int[] getCooldowns(ItemStack wand){
|
||||
|
||||
int[] cooldowns = new int[0];
|
||||
@@ -182,7 +192,7 @@ public final class WandHelper {
|
||||
// If there are no cooldowns, it is assumed that they are all zero and therefore nothing needs to be done.
|
||||
if(cooldowns.length == 0) return;
|
||||
|
||||
for(int i=0; i<cooldowns.length; i++){
|
||||
for(int i = 0; i < cooldowns.length; i++){
|
||||
if(cooldowns[i] > 0) cooldowns[i]--;
|
||||
}
|
||||
|
||||
@@ -215,8 +225,10 @@ public final class WandHelper {
|
||||
setCooldowns(wand, cooldowns);
|
||||
}
|
||||
|
||||
/** Returns the number of upgrades of the given type that have been applied to the given wand, or 0 if the wand has
|
||||
* no upgrade data or the given item is not a valid wand upgrade. */
|
||||
/**
|
||||
* Returns the number of upgrades of the given type that have been applied to the given wand, or 0 if the wand has
|
||||
* no upgrade data or the given item is not a valid wand upgrade.
|
||||
*/
|
||||
public static int getUpgradeLevel(ItemStack wand, Item upgrade){
|
||||
|
||||
String key = upgradeMap.get(upgrade);
|
||||
@@ -229,8 +241,10 @@ public final class WandHelper {
|
||||
|
||||
}
|
||||
|
||||
/** Returns the total number of upgrades that have been applied to the given wand, or 0 if the wand has no upgrade
|
||||
* data. */
|
||||
/**
|
||||
* Returns the total number of upgrades that have been applied to the given wand, or 0 if the wand has no upgrade
|
||||
* data.
|
||||
*/
|
||||
public static int getTotalUpgrades(ItemStack wand){
|
||||
|
||||
int totalUpgrades = 0;
|
||||
@@ -242,13 +256,16 @@ public final class WandHelper {
|
||||
return totalUpgrades;
|
||||
}
|
||||
|
||||
/** Applies the given upgrade to the given wand, or in other words increases the level for that upgrade by 1. This
|
||||
* does <b>not</b> account for the individual or total upgrade stack limits. */
|
||||
/**
|
||||
* Applies the given upgrade to the given wand, or in other words increases the level for that upgrade by 1. This
|
||||
* does <b>not</b> account for the individual or total upgrade stack limits.
|
||||
*/
|
||||
public static void applyUpgrade(ItemStack wand, Item upgrade){
|
||||
|
||||
if(wand.getTagCompound() == null) wand.setTagCompound((new NBTTagCompound()));
|
||||
|
||||
if(!wand.getTagCompound().hasKey(UPGRADES_KEY)) wand.getTagCompound().setTag(UPGRADES_KEY, new NBTTagCompound());
|
||||
if(!wand.getTagCompound().hasKey(UPGRADES_KEY))
|
||||
wand.getTagCompound().setTag(UPGRADES_KEY, new NBTTagCompound());
|
||||
|
||||
NBTTagCompound upgrades = wand.getTagCompound().getCompoundTag(UPGRADES_KEY);
|
||||
|
||||
@@ -258,35 +275,42 @@ public final class WandHelper {
|
||||
|
||||
wand.getTagCompound().setTag(UPGRADES_KEY, upgrades);
|
||||
}
|
||||
|
||||
|
||||
/** Returns true if the given item is a valid special wand upgrade. */
|
||||
public static boolean isWandUpgrade(Item upgrade){
|
||||
return upgradeMap.containsKey(upgrade);
|
||||
}
|
||||
|
||||
|
||||
/** Returns an unmodifiable set of all the items which are valid special wand upgrades. */
|
||||
public static Set<Item> getSpecialUpgrades(){
|
||||
return Collections.unmodifiableSet(WandHelper.upgradeMap.keySet());
|
||||
}
|
||||
|
||||
/** Package-protected getter for the identifier that corresponds to the given item, used only in the
|
||||
|
||||
/**
|
||||
* Package-protected getter for the identifier that corresponds to the given item, used only in the
|
||||
* {@link SpellModifiers} class. Internal to Wizardry.
|
||||
* @throws IllegalArgumentException if the given item is not a registered special wand upgrade.*/
|
||||
*
|
||||
* @throws IllegalArgumentException if the given item is not a registered special wand upgrade.
|
||||
*/
|
||||
static String getIdentifier(Item upgrade){
|
||||
if(!isWandUpgrade(upgrade)) throw new IllegalArgumentException("Tried to get a wand upgrade key for an item"
|
||||
+ "that is not a registered special wand upgrade.");
|
||||
if(!isWandUpgrade(upgrade)) throw new IllegalArgumentException(
|
||||
"Tried to get a wand upgrade key for an item" + "that is not a registered special wand upgrade.");
|
||||
return upgradeMap.get(upgrade);
|
||||
}
|
||||
|
||||
/** Registers a special upgrade with wizardry. Not used in the base mod, but I've put it here to make it easy
|
||||
* for add-ons to add new wand upgrades.
|
||||
|
||||
/**
|
||||
* Registers a special upgrade with wizardry. Not used in the base mod, but I've put it here to make it easy for
|
||||
* add-ons to add new wand upgrades.
|
||||
*
|
||||
* @param upgrade The wand upgrade item
|
||||
* @param identifier A unique string, used as a key for wand nbt tags
|
||||
* @throws IllegalArgumentException if the passed in identifier is already used for another wand upgrade */
|
||||
* @throws IllegalArgumentException if the passed in identifier is already used for another wand upgrade
|
||||
*/
|
||||
public static void registerSpecialUpgrade(Item upgrade, String identifier){
|
||||
// Throwing an exception is the best thing to do here, since if a duplicate was allowed weird things would
|
||||
// happen later with wand NBT.
|
||||
if(upgradeMap.containsValue(identifier)) throw new IllegalArgumentException("Duplicate wand upgrade identifier: " + identifier);
|
||||
if(upgradeMap.containsValue(identifier))
|
||||
throw new IllegalArgumentException("Duplicate wand upgrade identifier: " + identifier);
|
||||
upgradeMap.put(upgrade, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
package electroblob.wizardry.util;
|
||||
|
||||
/** Enum constants representing the different types of particle added by wizardry. This was renamed from the previous
|
||||
* EnumParticleType in the 1.10.2 port to avoid confusion with the vanilla version, EnumParticleTypes. */
|
||||
/**
|
||||
* Enum constants representing the different types of particle added by wizardry. This was renamed from the previous
|
||||
* EnumParticleType in the 1.10.2 port to avoid confusion with the vanilla version, EnumParticleTypes.
|
||||
*/
|
||||
public enum WizardryParticleType {
|
||||
BLIZZARD,
|
||||
BRIGHT_DUST,
|
||||
DARK_MAGIC,
|
||||
DUST,
|
||||
ICE,
|
||||
LEAF,
|
||||
MAGIC_BUBBLE,
|
||||
MAGIC_FIRE,
|
||||
PATH,
|
||||
SNOW,
|
||||
SPARK,
|
||||
SPARKLE,
|
||||
SPARKLE_ROTATING
|
||||
BLIZZARD, BRIGHT_DUST, DARK_MAGIC, DUST, ICE, LEAF, MAGIC_BUBBLE, MAGIC_FIRE, PATH, SNOW, SPARK, SPARKLE, SPARKLE_ROTATING
|
||||
}
|
||||
|
||||
@@ -15,124 +15,128 @@ import net.minecraft.pathfinding.PathPoint;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
/** Minecraft's pathfinder refused to play nicely, so I 'borrowed' its code and fiddled with it. Currently this is only
|
||||
* used for the {@link Clairvoyance} spell. */
|
||||
/**
|
||||
* Minecraft's pathfinder refused to play nicely, so I 'borrowed' its code and fiddled with it. Currently this is only
|
||||
* used for the {@link Clairvoyance} spell.
|
||||
*/
|
||||
public class WizardryPathFinder {
|
||||
|
||||
/** The path being generated */
|
||||
private final PathHeap path = new PathHeap();
|
||||
private final Set<PathPoint> closedSet = Sets.<PathPoint>newHashSet();
|
||||
/** Selection of path points to add to the path */
|
||||
private final PathPoint[] pathOptions = new PathPoint[32];
|
||||
private final NodeProcessor nodeProcessor;
|
||||
|
||||
public WizardryPathFinder(NodeProcessor processor){
|
||||
this.nodeProcessor = processor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Path findPath(IBlockAccess world, EntityLiving entity, BlockPos destination, float range){
|
||||
return this.findPath(world, entity, (double)((float)destination.getX() + 0.5F), (double)((float)destination.getY() + 0.5F), (double)((float)destination.getZ() + 0.5F), range);
|
||||
}
|
||||
/** The path being generated */
|
||||
private final PathHeap path = new PathHeap();
|
||||
private final Set<PathPoint> closedSet = Sets.<PathPoint>newHashSet();
|
||||
/** Selection of path points to add to the path */
|
||||
private final PathPoint[] pathOptions = new PathPoint[32];
|
||||
private final NodeProcessor nodeProcessor;
|
||||
|
||||
@Nullable
|
||||
private Path findPath(IBlockAccess world, EntityLiving entity, double x, double y, double z, float range){
|
||||
this.path.clearPath();
|
||||
this.nodeProcessor.initProcessor(world, entity);
|
||||
PathPoint pathpoint = this.nodeProcessor.getStart();
|
||||
PathPoint pathpoint1 = this.nodeProcessor.getPathPointToCoords(x, y, z);
|
||||
Path path = this.findPath(pathpoint, pathpoint1, range);
|
||||
this.nodeProcessor.postProcess();
|
||||
return path;
|
||||
}
|
||||
public WizardryPathFinder(NodeProcessor processor){
|
||||
this.nodeProcessor = processor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Path findPath(PathPoint start, PathPoint end, float range){
|
||||
|
||||
start.totalPathDistance = 0.0F;
|
||||
start.distanceToNext = start.distanceManhattan(end);
|
||||
start.distanceToTarget = start.distanceToNext;
|
||||
this.path.clearPath();
|
||||
this.closedSet.clear();
|
||||
this.path.addPoint(start);
|
||||
PathPoint pathpoint = start;
|
||||
int i = 0;
|
||||
@Nullable
|
||||
public Path findPath(IBlockAccess world, EntityLiving entity, BlockPos destination, float range){
|
||||
return this.findPath(world, entity, (double)((float)destination.getX() + 0.5F),
|
||||
(double)((float)destination.getY() + 0.5F), (double)((float)destination.getZ() + 0.5F), range);
|
||||
}
|
||||
|
||||
while(!this.path.isPathEmpty()){
|
||||
|
||||
++i;
|
||||
@Nullable
|
||||
private Path findPath(IBlockAccess world, EntityLiving entity, double x, double y, double z, float range){
|
||||
this.path.clearPath();
|
||||
this.nodeProcessor.initProcessor(world, entity);
|
||||
PathPoint pathpoint = this.nodeProcessor.getStart();
|
||||
PathPoint pathpoint1 = this.nodeProcessor.getPathPointToCoords(x, y, z);
|
||||
Path path = this.findPath(pathpoint, pathpoint1, range);
|
||||
this.nodeProcessor.postProcess();
|
||||
return path;
|
||||
}
|
||||
|
||||
// This is the offending line - timeout limit changed from 200 to 5000.
|
||||
if(i >= 5000){
|
||||
break;
|
||||
}
|
||||
@Nullable
|
||||
private Path findPath(PathPoint start, PathPoint end, float range){
|
||||
|
||||
PathPoint pathpoint1 = this.path.dequeue();
|
||||
start.totalPathDistance = 0.0F;
|
||||
start.distanceToNext = start.distanceManhattan(end);
|
||||
start.distanceToTarget = start.distanceToNext;
|
||||
this.path.clearPath();
|
||||
this.closedSet.clear();
|
||||
this.path.addPoint(start);
|
||||
PathPoint pathpoint = start;
|
||||
int i = 0;
|
||||
|
||||
if(pathpoint1.equals(end)){
|
||||
pathpoint = end;
|
||||
break;
|
||||
}
|
||||
while(!this.path.isPathEmpty()){
|
||||
|
||||
if(pathpoint1.distanceManhattan(end) < pathpoint.distanceManhattan(end)){
|
||||
pathpoint = pathpoint1;
|
||||
}
|
||||
++i;
|
||||
|
||||
pathpoint1.visited = true;
|
||||
int j = this.nodeProcessor.findPathOptions(this.pathOptions, pathpoint1, end, range);
|
||||
// This is the offending line - timeout limit changed from 200 to 5000.
|
||||
if(i >= 5000){
|
||||
break;
|
||||
}
|
||||
|
||||
for(int k = 0; k < j; ++k){
|
||||
|
||||
PathPoint pathpoint2 = this.pathOptions[k];
|
||||
float f = pathpoint1.distanceManhattan(pathpoint2);
|
||||
pathpoint2.distanceFromOrigin = pathpoint1.distanceFromOrigin + f;
|
||||
pathpoint2.cost = f + pathpoint2.costMalus;
|
||||
float f1 = pathpoint1.totalPathDistance + pathpoint2.cost;
|
||||
PathPoint pathpoint1 = this.path.dequeue();
|
||||
|
||||
if(pathpoint2.distanceFromOrigin < range && (!pathpoint2.isAssigned() || f1 < pathpoint2.totalPathDistance)){
|
||||
|
||||
pathpoint2.previous = pathpoint1;
|
||||
pathpoint2.totalPathDistance = f1;
|
||||
pathpoint2.distanceToNext = pathpoint2.distanceManhattan(end) + pathpoint2.costMalus;
|
||||
if(pathpoint1.equals(end)){
|
||||
pathpoint = end;
|
||||
break;
|
||||
}
|
||||
|
||||
if(pathpoint2.isAssigned()){
|
||||
this.path.changeDistance(pathpoint2, pathpoint2.totalPathDistance + pathpoint2.distanceToNext);
|
||||
}else{
|
||||
pathpoint2.distanceToTarget = pathpoint2.totalPathDistance + pathpoint2.distanceToNext;
|
||||
this.path.addPoint(pathpoint2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pathpoint1.distanceManhattan(end) < pathpoint.distanceManhattan(end)){
|
||||
pathpoint = pathpoint1;
|
||||
}
|
||||
|
||||
if(pathpoint == start){
|
||||
return null;
|
||||
}else{
|
||||
Path path = this.createEntityPath(start, pathpoint);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
pathpoint1.visited = true;
|
||||
int j = this.nodeProcessor.findPathOptions(this.pathOptions, pathpoint1, end, range);
|
||||
|
||||
/**
|
||||
* Returns a new PathEntity for a given start and end point
|
||||
*/
|
||||
private Path createEntityPath(PathPoint start, PathPoint end){
|
||||
|
||||
int i = 1;
|
||||
for(int k = 0; k < j; ++k){
|
||||
|
||||
for(PathPoint pathpoint = end; pathpoint.previous != null; pathpoint = pathpoint.previous){
|
||||
++i;
|
||||
}
|
||||
PathPoint pathpoint2 = this.pathOptions[k];
|
||||
float f = pathpoint1.distanceManhattan(pathpoint2);
|
||||
pathpoint2.distanceFromOrigin = pathpoint1.distanceFromOrigin + f;
|
||||
pathpoint2.cost = f + pathpoint2.costMalus;
|
||||
float f1 = pathpoint1.totalPathDistance + pathpoint2.cost;
|
||||
|
||||
PathPoint[] points = new PathPoint[i];
|
||||
PathPoint pathpoint1 = end;
|
||||
--i;
|
||||
if(pathpoint2.distanceFromOrigin < range
|
||||
&& (!pathpoint2.isAssigned() || f1 < pathpoint2.totalPathDistance)){
|
||||
|
||||
for(points[i] = end; pathpoint1.previous != null; points[i] = pathpoint1){
|
||||
pathpoint1 = pathpoint1.previous;
|
||||
--i;
|
||||
}
|
||||
pathpoint2.previous = pathpoint1;
|
||||
pathpoint2.totalPathDistance = f1;
|
||||
pathpoint2.distanceToNext = pathpoint2.distanceManhattan(end) + pathpoint2.costMalus;
|
||||
|
||||
return new Path(points);
|
||||
}
|
||||
if(pathpoint2.isAssigned()){
|
||||
this.path.changeDistance(pathpoint2, pathpoint2.totalPathDistance + pathpoint2.distanceToNext);
|
||||
}else{
|
||||
pathpoint2.distanceToTarget = pathpoint2.totalPathDistance + pathpoint2.distanceToNext;
|
||||
this.path.addPoint(pathpoint2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pathpoint == start){
|
||||
return null;
|
||||
}else{
|
||||
Path path = this.createEntityPath(start, pathpoint);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new PathEntity for a given start and end point
|
||||
*/
|
||||
private Path createEntityPath(PathPoint start, PathPoint end){
|
||||
|
||||
int i = 1;
|
||||
|
||||
for(PathPoint pathpoint = end; pathpoint.previous != null; pathpoint = pathpoint.previous){
|
||||
++i;
|
||||
}
|
||||
|
||||
PathPoint[] points = new PathPoint[i];
|
||||
PathPoint pathpoint1 = end;
|
||||
--i;
|
||||
|
||||
for(points[i] = end; pathpoint1.previous != null; points[i] = pathpoint1){
|
||||
pathpoint1 = pathpoint1.previous;
|
||||
--i;
|
||||
}
|
||||
|
||||
return new Path(points);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user