That's one heck of a commit you've got there...
I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here!
This commit is contained in:
@@ -1,11 +1,6 @@
|
||||
package electroblob.wizardry.entity.living;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
@@ -15,31 +10,18 @@ import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import electroblob.wizardry.util.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIHurtByTarget;
|
||||
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
|
||||
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
|
||||
import net.minecraft.entity.ai.EntityAIOpenDoor;
|
||||
import net.minecraft.entity.ai.EntityAIRestrictOpenDoor;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAIWander;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest2;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.ai.*;
|
||||
import net.minecraft.entity.monster.EntityMob;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagInt;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
@@ -55,13 +37,21 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
|
||||
|
||||
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<EntityEvilWizard>(this, 0.5D, 14.0F, 30, 50);
|
||||
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
|
||||
|
||||
public int textureIndex = 0;
|
||||
|
||||
public boolean hasTower = false;
|
||||
/** True if this evil wizard was spawned as part of a structure (tower or shrine), false if it spawned naturally. */
|
||||
public boolean hasStructure = false;
|
||||
|
||||
/** Stores the UUIDs of the other evil wizards spawned in the same group, if any. The wizard will not revenge-target
|
||||
* entities whose UUIDs are in this set. This is currently used only for shrines. */
|
||||
public final Set<UUID> groupUUIDs = new HashSet<>();
|
||||
|
||||
/** The entity selector passed into the new AI methods. */
|
||||
protected Predicate<Entity> targetSelector;
|
||||
@@ -95,11 +85,12 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
protected void entityInit(){
|
||||
super.entityInit();
|
||||
this.dataManager.register(HEAL_COOLDOWN, -1);
|
||||
this.dataManager.register(ELEMENT, 0);
|
||||
this.dataManager.register(ELEMENT, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEntityAI(){
|
||||
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(4, new EntityAIRestrictOpenDoor(this));
|
||||
this.tasks.addTask(5, new EntityAIOpenDoor(this, true));
|
||||
@@ -107,34 +98,31 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
this.tasks.addTask(7, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
|
||||
this.tasks.addTask(7, new EntityAIWander(this, 0.6D));
|
||||
|
||||
this.targetSelector = new Predicate<Entity>(){
|
||||
this.targetSelector = entity -> {
|
||||
|
||||
public boolean apply(Entity entity){
|
||||
// If the target is valid and not invisible...
|
||||
if(entity != null && !entity.isInvisible()
|
||||
&& AllyDesignationSystem.isValidTarget(EntityEvilWizard.this, entity)){
|
||||
|
||||
// If the target is valid and not invisible...
|
||||
if(entity != null && !entity.isInvisible()
|
||||
&& WizardryUtilities.isValidTarget(EntityEvilWizard.this, entity)){
|
||||
|
||||
// ... and is a player, a summoned creature, another (non-evil) wizard ...
|
||||
if(entity instanceof EntityPlayer
|
||||
|| (entity instanceof ISummonedCreature || entity instanceof EntityWizard
|
||||
// ... or in the whitelist ...
|
||||
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
|
||||
.contains(EntityList.getKey(entity.getClass())))
|
||||
// ... and isn't in the blacklist ...
|
||||
&& !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist)
|
||||
.contains(EntityList.getKey(entity.getClass()))){
|
||||
// ... it can be attacked.
|
||||
return true;
|
||||
}
|
||||
// ... and is a player, a summoned creature, another (non-evil) wizard ...
|
||||
if(entity instanceof EntityPlayer
|
||||
|| (entity instanceof ISummonedCreature || entity instanceof EntityWizard
|
||||
// ... or in the whitelist ...
|
||||
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
|
||||
.contains(EntityList.getKey(entity.getClass())))
|
||||
// ... and isn't in the blacklist ...
|
||||
&& !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist)
|
||||
.contains(EntityList.getKey(entity.getClass()))){
|
||||
// ... it can be attacked.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
|
||||
this.targetTasks.addTask(0, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(0, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.targetSelector));
|
||||
}
|
||||
|
||||
@@ -154,7 +142,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
}
|
||||
|
||||
public Element getElement(){
|
||||
return Element.values()[this.dataManager.get(ELEMENT)];
|
||||
int n = this.dataManager.get(ELEMENT);
|
||||
return n == -1 ? null : Element.values()[n];
|
||||
}
|
||||
|
||||
public void setElement(Element element){
|
||||
@@ -192,6 +181,11 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRevengeTarget(@Nullable EntityLivingBase target){
|
||||
if(target == null || !groupUUIDs.contains(target.getUniqueID())) super.setRevengeTarget(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLivingUpdate(){
|
||||
|
||||
@@ -225,13 +219,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
}
|
||||
}else{
|
||||
if(this.getHealth() < 10){
|
||||
// Wizards heal themseselves more often if they have low health
|
||||
// Wizards heal themselves more often if they have low health
|
||||
this.setHealCooldown(150);
|
||||
}else{
|
||||
this.setHealCooldown(400);
|
||||
}
|
||||
|
||||
this.playSound(WizardrySounds.SPELL_HEAL, 0.7F, rand.nextFloat() * 0.4F + 1.0F);
|
||||
this.playSound(Spells.heal.getSounds()[0], 0.7F, rand.nextFloat() * 0.4F + 1.0F);
|
||||
}
|
||||
}
|
||||
if(healCooldown > 0){
|
||||
@@ -250,8 +244,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// Spell.get(spells[3]).getDisplayName()));
|
||||
|
||||
// When right-clicked with a spell book in creative, sets one of the spells to that spell
|
||||
if(player.capabilities.isCreativeMode && stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.get(stack.getItemDamage());
|
||||
if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
||||
if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){
|
||||
// The set(...) method returns the element that was replaced - neat!
|
||||
player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard",
|
||||
@@ -269,8 +263,9 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
super.writeEntityToNBT(nbt);
|
||||
nbt.setInteger("element", this.getElement().ordinal());
|
||||
nbt.setInteger("skin", this.textureIndex);
|
||||
nbt.setTag("spells", WizardryUtilities.listToNBT(spells, spell -> new NBTTagInt(spell.id())));
|
||||
nbt.setBoolean("hasTower", this.hasTower);
|
||||
nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
|
||||
nbt.setBoolean("hasStructure", this.hasStructure);
|
||||
nbt.setTag("groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -278,9 +273,10 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
super.readEntityFromNBT(nbt);
|
||||
this.setElement(Element.values()[nbt.getInteger("element")]);
|
||||
this.textureIndex = nbt.getInteger("skin");
|
||||
this.spells = (List<Spell>)WizardryUtilities.NBTToList(nbt.getTagList("spells", NBT.TAG_INT),
|
||||
(NBTTagInt tag) -> Spell.get(tag.getInt()));
|
||||
this.hasTower = nbt.getBoolean("hasTower");
|
||||
this.spells = (List<Spell>)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT),
|
||||
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt()));
|
||||
this.hasStructure = nbt.getBoolean("hasStructure");
|
||||
this.groupUUIDs.addAll(NBTExtras.NBTToList(nbt.getTagList("groupUUIDs", NBT.TAG_COMPOUND), NBTUtil::getUUIDFromTag));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,7 +287,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
@Override
|
||||
public boolean getCanSpawnHere(){
|
||||
// Evil wizards can only spawn in the specified dimensions
|
||||
for(int id : Wizardry.settings.evilWizardDimensions){
|
||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
||||
if(this.dimension == id) return super.getCanSpawnHere();
|
||||
}
|
||||
|
||||
@@ -301,27 +297,27 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
@Override
|
||||
protected boolean canDespawn(){
|
||||
// Evil wizards can only despawn if they don't have a tower (i.e. if they spawned naturally at night)
|
||||
return !this.hasTower;
|
||||
return !this.hasStructure;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getSoundPitch(){
|
||||
return (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 0.6F;
|
||||
}
|
||||
// @Override
|
||||
// protected float getSoundPitch(){
|
||||
// return (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 0.6F;
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected SoundEvent getAmbientSound(){
|
||||
return SoundEvents.ENTITY_WITCH_AMBIENT;
|
||||
return WizardrySounds.ENTITY_EVIL_WIZARD_AMBIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoundEvent getHurtSound(DamageSource source){
|
||||
return SoundEvents.ENTITY_WITCH_HURT;
|
||||
return WizardrySounds.ENTITY_EVIL_WIZARD_HURT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoundEvent getDeathSound(){
|
||||
return SoundEvents.ENTITY_WITCH_DEATH;
|
||||
return WizardrySounds.ENTITY_EVIL_WIZARD_DEATH;
|
||||
}
|
||||
|
||||
// Although it *looks* like this is still called, in actual fact the only method that calls it is overridden in
|
||||
@@ -340,7 +336,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// the dropRareDrop method because that would be just as rare as normal mobs; instead this is half as rare.
|
||||
if(this.spells.size() > 0 && rand.nextInt(100) - lootingLevel < 5)
|
||||
this.entityDropItem(new ItemStack(WizardryItems.spell_book, 1,
|
||||
this.spells.get(1 + rand.nextInt(this.spells.size() - 1)).id()), 0);
|
||||
this.spells.get(1 + rand.nextInt(this.spells.size() - 1)).metadata()), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -355,17 +351,19 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
|
||||
textureIndex = this.rand.nextInt(6);
|
||||
|
||||
if(rand.nextBoolean()){
|
||||
this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]);
|
||||
}else{
|
||||
this.setElement(Element.MAGIC);
|
||||
if(getElement() == null){
|
||||
if(rand.nextBoolean()){
|
||||
this.setElement(Element.values()[rand.nextInt(Element.values().length - 1) + 1]);
|
||||
}else{
|
||||
this.setElement(Element.MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
Element element = this.getElement();
|
||||
|
||||
// Adds armour.
|
||||
for(EntityEquipmentSlot slot : WizardryUtilities.ARMOUR_SLOTS){
|
||||
this.setItemStackToSlot(slot, new ItemStack(WizardryUtilities.getArmour(element, slot)));
|
||||
this.setItemStackToSlot(slot, new ItemStack(WizardryItems.getArmour(element, slot)));
|
||||
}
|
||||
|
||||
// Default chance is 0.085f, for reference.
|
||||
@@ -375,12 +373,12 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// All wizards know magic missile, even if it is disabled.
|
||||
spells.add(Spells.magic_missile);
|
||||
|
||||
Tier maxTier = EntityWizard.populateSpells(spells, element, 3, rand);
|
||||
Tier maxTier = EntityWizard.populateSpells(spells, element, hasStructure, 3, rand);
|
||||
|
||||
// Now done after the spells so it can take the tier into account. For evil wizards this is slightly different;
|
||||
// it picks a random wand which is at least a high enough tier for the spells the wizard has.
|
||||
Tier tier = Tier.values()[maxTier.ordinal() + rand.nextInt(Tier.values().length - maxTier.ordinal())];
|
||||
this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryUtilities.getWand(tier, element)));
|
||||
this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(WizardryItems.getWand(tier, element)));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user