Merge branch '1.16.5' of https://github.com/FatherToast/SpecialMobs into 1.16.5

This commit is contained in:
Sarinsa 2022-06-30 14:44:36 +02:00
commit 4986eaf10d
21 changed files with 1366 additions and 37 deletions

View file

@ -40,6 +40,7 @@ public class ClientRegister {
registerFamilyRenderers( MobFamily.SILVERFISH, SpecialSilverfishRenderer::new ); registerFamilyRenderers( MobFamily.SILVERFISH, SpecialSilverfishRenderer::new );
registerFamilyRenderers( MobFamily.ENDERMAN, SpecialEndermanRenderer::new ); registerFamilyRenderers( MobFamily.ENDERMAN, SpecialEndermanRenderer::new );
//registerFamilyRenderers( MobFamily.WITCH, SpecialWitchRenderer::new ); //registerFamilyRenderers( MobFamily.WITCH, SpecialWitchRenderer::new );
registerFamilyRenderers( MobFamily.BLAZE, SpecialBlazeRenderer::new );
// Species overrides // Species overrides
registerSpeciesRenderer( NinjaSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new ); registerSpeciesRenderer( NinjaSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new );

View file

@ -0,0 +1,44 @@
package fathertoast.specialmobs.client.renderer.entity;
import com.mojang.blaze3d.matrix.MatrixStack;
import fathertoast.specialmobs.common.entity.ISpecialMob;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.entity.BlazeRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.entity.monster.BlazeEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@OnlyIn( Dist.CLIENT )
public class SpecialBlazeRenderer extends BlazeRenderer {
private final float baseShadowRadius;
public SpecialBlazeRenderer( EntityRendererManager rendererManager ) {
super( rendererManager );
baseShadowRadius = shadowRadius;
// Unneeded, the whole model is full brightness
//addLayer( new SpecialMobEyesLayer<>( this ) );
// Model doesn't support size parameter
//addLayer( new SpecialMobOverlayLayer<>( this, new SilverfishModel<>( 0.25F ) ) );
}
@Override
public ResourceLocation getTextureLocation( BlazeEntity entity ) {
return ((ISpecialMob<?>) entity).getSpecialData().getTexture();
}
@Override
protected void scale( BlazeEntity entity, MatrixStack matrixStack, float partialTick ) {
super.scale( entity, matrixStack, partialTick );
final float scale = ((ISpecialMob<?>) entity).getSpecialData().getRenderScale();
shadowRadius = baseShadowRadius * scale;
matrixStack.scale( scale, scale, scale );
}
}

View file

@ -27,12 +27,12 @@ public class SpecialCreeperRenderer extends CreeperRenderer {
public SpecialCreeperRenderer( EntityRendererManager rendererManager ) { public SpecialCreeperRenderer( EntityRendererManager rendererManager ) {
super( rendererManager ); super( rendererManager );
baseShadowRadius = shadowRadius; baseShadowRadius = shadowRadius;
// Get rid of this one since we have our own implementation
layers.removeIf( ( layer ) -> layer instanceof CreeperChargeLayer );
addLayer( new SpecialMobEyesLayer<>( this ) ); addLayer( new SpecialMobEyesLayer<>( this ) );
addLayer( new SpecialMobOverlayLayer<>( this, new CreeperModel<>( 0.25F ) ) ); addLayer( new SpecialMobOverlayLayer<>( this, new CreeperModel<>( 0.25F ) ) );
addLayer( new SpecialCreeperChargeLayer<>(this, new CreeperModel<>( 2.0F )) ); addLayer( new SpecialCreeperChargeLayer<>( this, new CreeperModel<>( 2.0F ) ) );
// Get rid of this one since we have our own implementation
layers.removeIf((layer) -> layer instanceof CreeperChargeLayer);
} }
@Override @Override

View file

@ -7,6 +7,7 @@ import fathertoast.specialmobs.common.entity.ISpecialMob;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.entity.EndermanRenderer; import net.minecraft.client.renderer.entity.EndermanRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.layers.EndermanEyesLayer;
import net.minecraft.client.renderer.entity.model.EndermanModel; import net.minecraft.client.renderer.entity.model.EndermanModel;
import net.minecraft.entity.monster.EndermanEntity; import net.minecraft.entity.monster.EndermanEntity;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@ -24,9 +25,11 @@ public class SpecialEndermanRenderer extends EndermanRenderer {
public SpecialEndermanRenderer( EntityRendererManager rendererManager ) { public SpecialEndermanRenderer( EntityRendererManager rendererManager ) {
super( rendererManager ); super( rendererManager );
layers.remove( layers.size() - 2 ); // Remove vanilla eyes layer // Get rid of this one since we have our own implementation
layers.removeIf( ( layer ) -> layer instanceof EndermanEyesLayer );
baseShadowRadius = shadowRadius; baseShadowRadius = shadowRadius;
//addLayer( new SpecialMobEyesLayer<>( this ) );//TODO temp until textures are fixed addLayer( new SpecialMobEyesLayer<>( this ) );
addLayer( new SpecialMobOverlayLayer<>( this, new EndermanModel<>( 0.25F ) ) ); addLayer( new SpecialMobOverlayLayer<>( this, new EndermanModel<>( 0.25F ) ) );
} }

View file

@ -1,7 +1,6 @@
package fathertoast.specialmobs.client.renderer.entity; package fathertoast.specialmobs.client.renderer.entity;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
import fathertoast.specialmobs.common.entity.ISpecialMob; import fathertoast.specialmobs.common.entity.ISpecialMob;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
@ -23,7 +22,8 @@ public class SpecialMagmaCubeRenderer extends MagmaCubeRenderer {
public SpecialMagmaCubeRenderer( EntityRendererManager rendererManager ) { public SpecialMagmaCubeRenderer( EntityRendererManager rendererManager ) {
super( rendererManager ); super( rendererManager );
baseShadowRadius = shadowRadius; baseShadowRadius = shadowRadius;
addLayer( new SpecialMobEyesLayer<>( this ) ); // Unneeded, the whole model is full brightness
//addLayer( new SpecialMobEyesLayer<>( this ) );
// Model doesn't support size parameter // Model doesn't support size parameter
//addLayer( new SpecialMobOverlayLayer<>( this, new MagmaCubeModel<>( 0.25F ) ) ); //addLayer( new SpecialMobOverlayLayer<>( this, new MagmaCubeModel<>( 0.25F ) ) );
} }

View file

@ -6,6 +6,7 @@ import fathertoast.specialmobs.common.entity.ISpecialMob;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.SpiderRenderer; import net.minecraft.client.renderer.entity.SpiderRenderer;
import net.minecraft.client.renderer.entity.layers.SpiderEyesLayer;
import net.minecraft.entity.monster.SpiderEntity; import net.minecraft.entity.monster.SpiderEntity;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
@ -22,7 +23,9 @@ public class SpecialSpiderRenderer extends SpiderRenderer<SpiderEntity> {
public SpecialSpiderRenderer( EntityRendererManager rendererManager ) { public SpecialSpiderRenderer( EntityRendererManager rendererManager ) {
super( rendererManager ); super( rendererManager );
layers.remove( layers.size() - 1 ); // Remove vanilla eyes layer // Get rid of this one since we have our own implementation
layers.removeIf( ( layer ) -> layer instanceof SpiderEyesLayer );
baseShadowRadius = shadowRadius; baseShadowRadius = shadowRadius;
addLayer( new SpecialMobEyesLayer<>( this ) ); addLayer( new SpecialMobEyesLayer<>( this ) );
// Model doesn't support size parameter // Model doesn't support size parameter

View file

@ -100,10 +100,10 @@ public class MobFamily<T extends LivingEntity> {
// "Baby", "Fighter", "King", "Queen", "Unholy" // "Baby", "Fighter", "King", "Queen", "Unholy"
// ); // );
// public static final MobFamily<BlazeEntity> BLAZE = new MobFamily<>( public static final MobFamily<BlazeEntity> BLAZE = new MobFamily<>(
// "Blaze", "blazes", 0xF6B201, new EntityType[] { EntityType.BLAZE }, "Blaze", "blazes", 0xF6B201, new EntityType[] { EntityType.BLAZE },
// "Cinder", "Conflagration", "Ember", "Hellfire", "Inferno", "Jolt", "Wildfire" "Cinder", "Conflagration", "Ember", "Hellfire", "Inferno", "Jolt", "Wildfire"
// ); );
static { static {
final HashMap<EntityType<?>, MobFamily<?>> classToFamilyMap = new HashMap<>(); final HashMap<EntityType<?>, MobFamily<?>> classToFamilyMap = new HashMap<>();

View file

@ -0,0 +1,102 @@
package fathertoast.specialmobs.common.entity.ai;
import fathertoast.specialmobs.common.entity.SpecialMobData;
import fathertoast.specialmobs.common.entity.blaze._SpecialBlazeEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.Goal;
import java.util.EnumSet;
/**
* The attack AI used by blazes. This handles both ranged and melee behaviors.
*/
public class SpecialBlazeAttackGoal extends Goal {
private final _SpecialBlazeEntity blaze;
private int attackStep;
private int attackTime;
private int lastSeen;
public SpecialBlazeAttackGoal( _SpecialBlazeEntity entity ) {
blaze = entity;
setFlags( EnumSet.of( Goal.Flag.MOVE, Goal.Flag.LOOK ) );
}
/** @return Returns true if this AI can be activated. */
@Override
public boolean canUse() {
final LivingEntity target = blaze.getTarget();
return target != null && target.isAlive() && blaze.canAttack( target );
}
/** Called when this AI is activated. */
@Override
public void start() {
attackStep = 0;
}
/** Called when this AI is deactivated. */
@Override
public void stop() {
blaze.setCharged( false );
lastSeen = 0;
}
/** Called each tick while this AI is active. */
@Override
public void tick() {
attackTime--;
final LivingEntity target = blaze.getTarget();
if( target == null ) return;
final SpecialMobData<_SpecialBlazeEntity> data = blaze.getSpecialData();
final boolean canSee = blaze.getSensing().canSee( target );
if( canSee ) lastSeen = 0;
else lastSeen++;
final double distanceSqr = blaze.distanceToSqr( target );
final float rangeSq = data.rangedAttackMaxRange * data.rangedAttackMaxRange;
if( distanceSqr < getAttackReachSqr( target ) ) {
if( canSee && attackTime <= 0 ) {
attackTime = 20;
blaze.doHurtTarget( target );
}
blaze.getMoveControl().setWantedPosition( target.getX(), target.getY(), target.getZ(), 1.0 );
}
else if( distanceSqr < rangeSq && canSee ) {
if( attackTime <= 0 ) {
attackStep++;
if( attackStep == 1 ) {
attackTime = data.rangedAttackMaxCooldown - data.rangedAttackCooldown;
blaze.setCharged( true );
}
else if( attackStep <= 1 + blaze.fireballBurstCount ) {
attackTime = blaze.fireballBurstDelay;
}
else {
attackTime = data.rangedAttackCooldown;
attackStep = 0;
blaze.setCharged( false );
}
if( attackStep > 1 ) {
blaze.performRangedAttack( target, attackStep );
}
}
blaze.getLookControl().setLookAt( target, 10.0F, 10.0F );
}
else if( lastSeen < 5 ) {
blaze.getMoveControl().setWantedPosition( target.getX(), target.getY(), target.getZ(), 1.0 );
}
super.tick();
}
protected double getAttackReachSqr( LivingEntity target ) {
return blaze.getBbWidth() * blaze.getBbWidth() * 4.0F + target.getBbWidth() + 2.0F;
}
}

View file

@ -0,0 +1,78 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.item.Items;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class CinderBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<CinderBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.5F, 0.9F );
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.DISABLED );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.ATTACK_DAMAGE, -2.0 )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Cinder",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
loot.addCommonDrop( "common", Items.BLAZE_POWDER, 1 );
}
@SpecialMob.Factory
public static EntityType.IFactory<CinderBlazeEntity> getVariantFactory() { return CinderBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
public CinderBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 0.5F );
xpReward = 1;
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
getSpecialData().rangedAttackDamage -= 1.0F;
disableRangedAI();
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
target.setSecondsOnFire( 4 );
}
}

View file

@ -0,0 +1,141 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.MobHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance;
import net.minecraft.entity.projectile.SnowballEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.potion.PotionUtils;
import net.minecraft.potion.Potions;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.UUID;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<ConflagrationBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.9F, 2.7F );
return new BestiaryInfo( 0xFFF87E, BestiaryInfo.BaseWeight.LOW );
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Conflagration",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.FIRE_CHARGE );
loot.addRareDrop( "rare", PotionUtils.setPotion( new ItemStack( Items.POTION ), Potions.FIRE_RESISTANCE ) );
}
@SpecialMob.Factory
public static EntityType.IFactory<ConflagrationBlazeEntity> getVariantFactory() { return ConflagrationBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
/** The damage boost to apply from growth level. */
private static final AttributeModifier DAMAGE_BOOST = new AttributeModifier( UUID.fromString( "70457CAB-AA09-4E1C-B44B-99DD4A2A836D" ),
"Feeding damage boost", 1.0, AttributeModifier.Operation.ADDITION );
/** The level of increased attack damage gained. */
private int growthLevel;
public ConflagrationBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
xpReward += 4;
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
if( target instanceof LivingEntity ) {
MobHelper.stealLife( this, (LivingEntity) target, 2.0F );
}
}
/** @return Attempts to damage this entity; returns true if the hit was successful. */
@Override
public boolean hurt( DamageSource source, float amount ) {
if( isInvulnerableTo( source ) || fireImmune() && source.isFire() ) return false;
if( !source.isExplosion() && !source.isMagic() && !DamageSource.DROWN.getMsgId().equals( source.getMsgId() ) &&
!(source.getDirectEntity() instanceof SnowballEntity) ) {
if( !level.isClientSide() && growthLevel < 7 ) {
growthLevel++;
getSpecialData().rangedAttackDamage += 0.5F;
getSpecialData().rangedAttackCooldown -= 4;
getSpecialData().rangedAttackMaxCooldown -= 4;
if( growthLevel == 7 ) fireballBurstCount++;
updateFeedingLevels();
}
amount /= 2.0F;
}
return super.hurt( source, amount );
}
/** Recalculates the modifiers associated with this entity's feeding level counters. */
private void updateFeedingLevels() {
if( level != null && !level.isClientSide ) {
final ModifiableAttributeInstance damage = getAttribute( Attributes.ATTACK_DAMAGE );
//noinspection ConstantConditions
damage.removeModifier( DAMAGE_BOOST.getId() );
if( growthLevel > 0 ) {
damage.addPermanentModifier( new AttributeModifier( DAMAGE_BOOST.getId(), DAMAGE_BOOST.getName(),
DAMAGE_BOOST.getAmount() * growthLevel, DAMAGE_BOOST.getOperation() ) );
}
}
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_GROWTH_LEVEL, (byte) growthLevel );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_GROWTH_LEVEL, References.NBT_TYPE_NUMERICAL ) )
growthLevel = saveTag.getByte( References.TAG_GROWTH_LEVEL );
updateFeedingLevels();
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "conflagration" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,89 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.MobHelper;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.item.Items;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class EmberBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<EmberBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0x000000 );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
.addAttribute( Attributes.ARMOR, 10.0 )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Ember",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.COAL, 1 );
}
@SpecialMob.Factory
public static EntityType.IFactory<EmberBlazeEntity> getVariantFactory() { return EmberBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
public EmberBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
xpReward += 2;
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
disableRangedAI();
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
if( target instanceof LivingEntity ) {
MobHelper.causeLifeLoss( (LivingEntity) target, 2.0F );
}
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "ember" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,116 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.projectile.FireballEntity;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class HellfireBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<HellfireBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.7F, 1.99F );
return new BestiaryInfo( 0xDDDDDD );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Hellfire",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.GUNPOWDER );
}
@SpecialMob.Factory
public static EntityType.IFactory<HellfireBlazeEntity> getVariantFactory() { return HellfireBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
/** The base explosion strength of this blaze's fireballs. */
private int explosionPower = 2;
public HellfireBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.1F );
xpReward += 2;
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
getSpecialData().rangedAttackSpread = 0.0F;
setRangedAI( 1, 0, 60, 100, 40.0F );
}
/** Called to attack the target with a ranged attack. */
@Override
public void performRangedAttack( LivingEntity target, float damageMulti ) {
if( !isSilent() ) level.levelEvent( null, 1018, blockPosition(), 0 );
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * getSpecialData().rangedAttackSpread / 28.0F;
final double dX = target.getX() - getX() + getRandom().nextGaussian() * accelVariance;
final double dY = target.getY( 0.5 ) - getY( 0.5 );
final double dZ = target.getZ() - getZ() + getRandom().nextGaussian() * accelVariance;
final FireballEntity fireball = new FireballEntity( level, this, dX, dY, dZ );
fireball.explosionPower = explosionPower;
fireball.setPos( fireball.getX(), getY( 0.5 ) + 0.5, fireball.getZ() );
level.addFreshEntity( fireball );
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_EXPLOSION_POWER, (byte) explosionPower );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_EXPLOSION_POWER, References.NBT_TYPE_NUMERICAL ) )
explosionPower = saveTag.getByte( References.TAG_EXPLOSION_POWER );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "hellfire" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,89 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.MobHelper;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.item.Items;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class InfernoBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<InfernoBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xF14F00 );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Inferno",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.BLAZE_POWDER );
loot.addSemicommonDrop( "semicommon", Items.FIRE_CHARGE );
}
@SpecialMob.Factory
public static EntityType.IFactory<InfernoBlazeEntity> getVariantFactory() { return InfernoBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
public InfernoBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
xpReward += 2;
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
getSpecialData().rangedAttackSpread *= 3.0F;
setRangedAI( 12, 2, 80, 100, 20.0F );
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
if( target instanceof LivingEntity ) {
MobHelper.causeLifeLoss( (LivingEntity) target, 2.0F );
}
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "inferno" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,189 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.MobHelper;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.ExplosionHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.effect.LightningBoltEntity;
import net.minecraft.item.Items;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction;
import net.minecraft.util.IndirectEntityDamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.entity.living.EntityTeleportEvent;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class JoltBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<JoltBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0x499CAE );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
.addAttribute( Attributes.ARMOR, 10.0 )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Jolt",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.REDSTONE );
}
@SpecialMob.Factory
public static EntityType.IFactory<JoltBlazeEntity> getVariantFactory() { return JoltBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
public JoltBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
xpReward += 2;
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
disableRangedAI();
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
if( target instanceof LivingEntity ) {
MobHelper.causeLifeLoss( (LivingEntity) target, 2.0F );
}
}
/** Called each tick to update this entity's movement. */
@Override
public void aiStep() {
if( !level.isClientSide() && isAlive() && getTarget() != null && random.nextInt( 20 ) == 0 &&
distanceToSqr( getTarget() ) > 256.0 ) {
for( int i = 0; i < 16; i++ ) {
if( teleportTowards( getTarget() ) ) break;
}
}
super.aiStep();
}
/** @return Attempts to damage this entity; returns true if the hit was successful. */
@Override
public boolean hurt( DamageSource source, float amount ) {
if( isInvulnerableTo( source ) || fireImmune() && source.isFire() ) return false;
if( source instanceof IndirectEntityDamageSource ) {
for( int i = 0; i < 64; i++ ) {
if( teleport() ) return true;
}
return false;
}
final boolean success = super.hurt( source, amount );
if( !level.isClientSide() && getHealth() > 0.0F ) {
if( source.getEntity() instanceof LivingEntity ) {
for( int i = 0; i < 16; i++ ) {
if( teleport() ) break;
}
}
else if( random.nextInt( 10 ) != 0 ) {
teleport();
}
}
return success;
}
/** @return Teleports this "enderman" to a random nearby position; returns true if successful. */
protected boolean teleport() {
if( level.isClientSide() || !isAlive() ) return false;
final double x = getX() + (random.nextDouble() - 0.5) * 32.0;
final double y = getY() + (double) (random.nextInt( 16 ) - 8);
final double z = getZ() + (random.nextDouble() - 0.5) * 32.0;
return teleport( x, y, z );
}
/** @return Teleports this "enderman" towards another entity; returns true if successful. */
protected boolean teleportTowards( Entity target ) {
final Vector3d directionFromTarget = new Vector3d(
getX() - target.getX(),
getY( 0.5 ) - target.getEyeY(),
getZ() - target.getZ() )
.normalize();
final double x = getX() + (random.nextDouble() - 0.5) * 8.0 - directionFromTarget.x * 16.0;
final double y = getY() + (double) (random.nextInt( 8 ) - 2) - directionFromTarget.y * 16.0;
final double z = getZ() + (random.nextDouble() - 0.5) * 8.0 - directionFromTarget.z * 16.0;
return teleport( x, y, z );
}
/** @return Teleports this "enderman" to a new position; returns true if successful. */
protected boolean teleport( double x, double y, double z ) {
final BlockPos.Mutable pos = new BlockPos.Mutable( x, y, z );
while( pos.getY() > 0 && !level.getBlockState( pos ).getMaterial().blocksMotion() ) {
pos.move( Direction.DOWN );
}
final BlockState block = level.getBlockState( pos );
if( !block.getMaterial().blocksMotion() || block.getFluidState().is( FluidTags.WATER ) ) return false;
EntityTeleportEvent.EnderEntity event = ForgeEventFactory.onEnderTeleport( this, x, y, z );
if( event.isCanceled() ) return false;
final boolean success = randomTeleport( event.getTargetX(), event.getTargetY(), event.getTargetZ(), false );
if( success ) {
ExplosionHelper.spawnLightning( level, xo, yo, zo );
ExplosionHelper.spawnLightning( level, getX(), getY(), getZ() );
}
return success;
}
/** Called when this entity is struck by lightning. */
@Override
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { }
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "jolt" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,169 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.util.AttributeHelper;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class WildfireBlazeEntity extends _SpecialBlazeEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<WildfireBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.9F, 2.7F );
return new BestiaryInfo( 0xF4EE32 );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Wildfire",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.COAL, 1 );
loot.addUncommonDrop( "uncommon", Items.BLAZE_SPAWN_EGG );
}
@SpecialMob.Factory
public static EntityType.IFactory<WildfireBlazeEntity> getVariantFactory() { return WildfireBlazeEntity::new; }
//--------------- Variant-Specific Implementations ----------------
/** The number of babies spawned on death. */
private int babies;
/** The number of extra babies that can be spawned by attacks. */
private int extraBabies;
public WildfireBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
getSpecialData().setRegenerationTime( 40 );
xpReward += 2;
babies = 2 + random.nextInt( 3 );
extraBabies = 3 + random.nextInt( 4 );
}
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
getSpecialData().rangedAttackSpread *= 0.1F;
setRangedAI( 1, 0, 30, 50, 20.0F );
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) {
target.setSecondsOnFire( 8 );
}
/** Called to attack the target with a ranged attack. */
@Override
public void performRangedAttack( LivingEntity target, float damageMulti ) {
if( !level.isClientSide() && extraBabies > 0 && random.nextInt( 2 ) == 0 ) {
extraBabies--;
final double vX = target.getX() - getX();
final double vZ = target.getZ() - getZ();
final double vH = Math.sqrt( vX * vX + vZ * vZ );
spawnBaby( vX / vH * 0.8 + getDeltaMovement().x * 0.2, vZ / vH * 0.8 + getDeltaMovement().z * 0.2, null );
spawnAnim();
if( !isSilent() ) level.levelEvent( null, 1018, blockPosition(), 0 );
}
else {
super.performRangedAttack( target, damageMulti );
}
}
/** Called to remove this entity from the world. Includes death, unloading, interdimensional travel, etc. */
@Override
public void remove( boolean keepData ) {
//noinspection deprecation
if( isDeadOrDying() && !removed && level instanceof IServerWorld ) { // Same conditions as slime splitting
// Spawn babies on death
final int babiesToSpawn = babies + extraBabies;
ILivingEntityData groupData = null;
for( int i = 0; i < babiesToSpawn; i++ ) {
groupData = spawnBaby( (random.nextDouble() - 0.5) * 0.3, (random.nextDouble() - 0.5) * 0.3, groupData );
}
spawnAnim();
if( !isSilent() ) level.levelEvent( null, 1018, blockPosition(), 0 );
}
super.remove( keepData );
}
/** Helper method to simplify spawning babies. */
@Nullable
private ILivingEntityData spawnBaby( double vX, double vZ, @Nullable ILivingEntityData groupData ) {
final CinderBlazeEntity baby = CinderBlazeEntity.SPECIES.entityType.get().create( level );
if( baby == null ) return groupData;
baby.copyPosition( this );
baby.yHeadRot = yRot;
baby.yBodyRot = yRot;
groupData = baby.finalizeSpawn( (IServerWorld) level, level.getCurrentDifficultyAt( blockPosition() ),
SpawnReason.MOB_SUMMONED, groupData, null );
baby.setTarget( getTarget() );
baby.setDeltaMovement( vX, 0.0, vZ );
baby.setOnGround( false );
level.addFreshEntity( baby );
return groupData;
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_BABIES, (byte) babies );
saveTag.putByte( References.TAG_EXTRA_BABIES, (byte) extraBabies );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_BABIES, References.NBT_TYPE_NUMERICAL ) )
babies = saveTag.getByte( References.TAG_BABIES );
if( saveTag.contains( References.TAG_EXTRA_BABIES, References.NBT_TYPE_NUMERICAL ) )
extraBabies = saveTag.getByte( References.TAG_EXTRA_BABIES );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "wildfire" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,297 @@
package fathertoast.specialmobs.common.entity.blaze;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.core.SpecialMobs;
import fathertoast.specialmobs.common.entity.ISpecialMob;
import fathertoast.specialmobs.common.entity.SpecialMobData;
import fathertoast.specialmobs.common.entity.ai.AIHelper;
import fathertoast.specialmobs.common.entity.ai.SpecialBlazeAttackGoal;
import fathertoast.specialmobs.common.entity.ai.SpecialHurtByTargetGoal;
import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.BlockState;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.monster.BlazeEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.SmallFireballEntity;
import net.minecraft.entity.projectile.SnowballEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.potion.EffectInstance;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob, ISpecialMob<_SpecialBlazeEntity> {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.SpeciesReference
public static MobFamily.Species<_SpecialBlazeEntity> SPECIES;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xFFF87E ); //TODO - TEMP: base size = 0.6F, 1.8F
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return BlazeEntity.createAttributes();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Blaze",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void addBaseLoot( LootTableBuilder loot ) {
loot.addLootTable( "main", EntityType.BLAZE.getDefaultLootTable() );
}
@SpecialMob.Factory
public static EntityType.IFactory<_SpecialBlazeEntity> getFactory() { return _SpecialBlazeEntity::new; }
//--------------- Variant-Specific Breakouts ----------------
public _SpecialBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().initialize();
getSpecialData().setDamagedByWater( true );
}
/** Called in the MobEntity.class constructor to initialize AI goals. */
@Override
protected void registerGoals() {
super.registerGoals();
AIHelper.removeGoals( goalSelector, 4 ); // BlazeEntity.FireballAttackGoal
goalSelector.addGoal( 4, new SpecialBlazeAttackGoal( this ) );
AIHelper.replaceHurtByTarget( this, new SpecialHurtByTargetGoal( this, BlazeEntity.class ).setAlertOthers() );
setRangedAI( 3, 6, 60, 100, 48.0F );
registerVariantGoals();
}
/** Override to change this entity's AI goals. */
protected void registerVariantGoals() { }
/** Helper method to set the ranged attack AI more easily. */
protected void disableRangedAI() {
setRangedAI( 0, 6, 60, 100, 0.0F );
}
/** Helper method to set the ranged attack AI more easily. */
protected void setRangedAI( int burstCount, int burstDelay, int chargeTime, int cooldownTime, float range ) {
fireballBurstCount = burstCount;
fireballBurstDelay = burstDelay;
getSpecialData().rangedAttackCooldown = cooldownTime;
getSpecialData().rangedAttackMaxCooldown = cooldownTime + chargeTime;
getSpecialData().rangedAttackMaxRange = range;
}
/** Called when this entity successfully damages a target to apply on-hit effects. */
@Override
public void doEnchantDamageEffects( LivingEntity attacker, Entity target ) {
onVariantAttack( target );
super.doEnchantDamageEffects( attacker, target );
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) { }
/** Override to save data to this entity's NBT data. */
public void addVariantSaveData( CompoundNBT saveTag ) { }
/** Override to load data from this entity's NBT data. */
public void readVariantSaveData( CompoundNBT saveTag ) { }
//--------------- Family-Specific Implementations ----------------
/** The parameter for special mob render scale. */
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialBlazeEntity.class, DataSerializers.FLOAT );
// The amount of fireballs in each burst.
public int fireballBurstCount;
// The ticks between each shot in a burst.
public int fireballBurstDelay;
/** Called from the Entity.class constructor to define data watcher variables. */
@Override
protected void defineSynchedData() {
super.defineSynchedData();
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
}
/** Called to attack the target with a ranged attack. */
@Override
public void performRangedAttack( LivingEntity target, float damageMulti ) {
if( !isSilent() ) level.levelEvent( null, 1018, blockPosition(), 0 );
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * getSpecialData().rangedAttackSpread / 28.0F;
final double dX = target.getX() - getX() + getRandom().nextGaussian() * accelVariance;
final double dY = target.getY( 0.5 ) - getY( 0.5 );
final double dZ = target.getZ() - getZ() + getRandom().nextGaussian() * accelVariance;
final SmallFireballEntity fireball = new SmallFireballEntity( level, this, dX, dY, dZ );
fireball.setPos( fireball.getX(), getY( 0.5 ) + 0.5, fireball.getZ() );
level.addFreshEntity( fireball );
}
/** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
@Nullable
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
groupData = super.finalizeSpawn( world, difficulty, spawnReason, groupData, eggTag );
// TODO ranged attack
return groupData;
}
//--------------- ISpecialMob Implementation ----------------
private SpecialMobData<_SpecialBlazeEntity> specialData;
/** @return This mob's special data. */
@Override
public SpecialMobData<_SpecialBlazeEntity> getSpecialData() { return specialData; }
/** @return The experience that should be dropped by this entity. */
@Override
public final int getExperience() { return xpReward; }
/** Sets the experience that should be dropped by this entity. */
@Override
public final void setExperience( int xp ) { xpReward = xp; }
static ResourceLocation GET_TEXTURE_PATH( String type ) {
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "blaze/" + type + ".png" );
}
private static final ResourceLocation[] TEXTURES = { new ResourceLocation( "textures/entity/blaze.png" ) };
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
//--------------- SpecialMobData Hooks ----------------
/** Called each tick to update this entity's movement. */
@Override
public void aiStep() {
super.aiStep();
getSpecialData().tick();
}
/** @return The eye height of this entity when standing. */
@Override
protected float getStandingEyeHeight( Pose pose, EntitySize size ) {
return super.getStandingEyeHeight( pose, size ) * getSpecialData().getBaseScale() * (isBaby() ? 0.53448F : 1.0F);
}
/** @return Whether this entity is immune to fire damage. */
@Override
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
/** Sets this entity on fire for a specific duration. */
@Override
public void setRemainingFireTicks( int ticks ) {
if( !getSpecialData().isImmuneToBurning() ) super.setRemainingFireTicks( ticks );
}
/** @return True if this entity can be leashed. */
@Override
public boolean canBeLeashed( PlayerEntity player ) { return !isLeashed() && getSpecialData().allowLeashing(); }
/** Sets this entity 'stuck' inside a block, such as a cobweb or sweet berry bush. Mod blocks could use this as a speed boost. */
@Override
public void makeStuckInBlock( BlockState block, Vector3d speedMulti ) {
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
}
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
@Override
public boolean causeFallDamage( float distance, float damageMultiplier ) {
return super.causeFallDamage( distance, damageMultiplier * getSpecialData().getFallDamageMultiplier() );
}
/** @return True if this entity should NOT trigger pressure plates or tripwires. */
@Override
public boolean isIgnoringBlockTriggers() { return getSpecialData().ignorePressurePlates(); }
/** @return True if this entity can breathe underwater. */
@Override
public boolean canBreatheUnderwater() { return getSpecialData().canBreatheInWater(); }
/** @return True if this entity can be pushed by (flowing) fluids. */
@Override
public boolean isPushedByFluid() { return !getSpecialData().ignoreWaterPush(); }
/** @return True if this entity takes damage while wet. */
@Override
public boolean isSensitiveToWater() { return getSpecialData().isDamagedByWater(); }
/** @return Attempts to damage this entity; returns true if the hit was successful. */
@Override
public boolean hurt( DamageSource source, float amount ) {
if( source.getDirectEntity() instanceof SnowballEntity ) {
if( isSensitiveToWater() ) amount = Math.max( 3.0F, amount );
else amount = 0.0F; // Allow blazes to be insensitive to snowballs
}
return super.hurt( source, amount );
}
/** @return True if the effect can be applied to this entity. */
@Override
public boolean canBeAffected( EffectInstance effect ) { return getSpecialData().isPotionApplicable( effect ); }
/** Saves data to this entity's base NBT compound that is specific to its subclass. */
@Override
public void addAdditionalSaveData( CompoundNBT tag ) {
super.addAdditionalSaveData( tag );
final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag );
saveTag.putByte( References.TAG_BURST_COUNT, (byte) fireballBurstCount );
saveTag.putByte( References.TAG_BURST_DELAY, (byte) fireballBurstDelay );
getSpecialData().writeToNBT( saveTag );
addVariantSaveData( saveTag );
}
/** Loads data from this entity's base NBT compound that is specific to its subclass. */
@Override
public void readAdditionalSaveData( CompoundNBT tag ) {
super.readAdditionalSaveData( tag );
final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag );
if( saveTag.contains( References.TAG_BURST_COUNT, References.NBT_TYPE_NUMERICAL ) )
fireballBurstCount = saveTag.getByte( References.TAG_BURST_COUNT );
if( saveTag.contains( References.TAG_BURST_DELAY, References.NBT_TYPE_NUMERICAL ) )
fireballBurstDelay = saveTag.getByte( References.TAG_BURST_DELAY );
getSpecialData().readFromNBT( saveTag );
readVariantSaveData( saveTag );
}
}

View file

@ -189,8 +189,8 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
/** Called when this entity is struck by lightning. */ /** Called when this entity is struck by lightning. */
@Override @Override
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) {
if (!isPowered() && random.nextDouble() < 0.1D) if( !isPowered() && random.nextDouble() < 0.1D )
setSupercharged(true); setSupercharged( true );
super.thunderHit( world, lightningBolt ); super.thunderHit( world, lightningBolt );
@ -387,6 +387,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag ); final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag );
saveTag.putBoolean( References.TAG_SUPERCHARGED, isSupercharged() ); saveTag.putBoolean( References.TAG_SUPERCHARGED, isSupercharged() );
saveTag.putBoolean( References.TAG_DRY_EXPLODE, cannotExplodeWhileWet() ); saveTag.putBoolean( References.TAG_DRY_EXPLODE, cannotExplodeWhileWet() );
saveTag.putBoolean( References.TAG_WHEN_BURNING_EXPLODE, explodesWhileBurning() ); saveTag.putBoolean( References.TAG_WHEN_BURNING_EXPLODE, explodesWhileBurning() );
saveTag.putBoolean( References.TAG_WHEN_SHOT_EXPLODE, explodesWhenShot() ); saveTag.putBoolean( References.TAG_WHEN_SHOT_EXPLODE, explodesWhenShot() );
@ -402,7 +403,8 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag ); final CompoundNBT saveTag = SpecialMobData.getSaveLocation( tag );
setSupercharged( saveTag.getBoolean(References.TAG_SUPERCHARGED) ); if( saveTag.contains( References.TAG_SUPERCHARGED, References.NBT_TYPE_NUMERICAL ) )
setSupercharged( saveTag.getBoolean( References.TAG_SUPERCHARGED ) );
if( saveTag.contains( References.TAG_DRY_EXPLODE, References.NBT_TYPE_NUMERICAL ) ) if( saveTag.contains( References.TAG_DRY_EXPLODE, References.NBT_TYPE_NUMERICAL ) )
setCannotExplodeWhileWet( saveTag.getBoolean( References.TAG_DRY_EXPLODE ) ); setCannotExplodeWhileWet( saveTag.getBoolean( References.TAG_DRY_EXPLODE ) );

View file

@ -71,13 +71,6 @@ public class HungrySpiderEntity extends _SpecialSpiderEntity {
//--------------- Variant-Specific Implementations ---------------- //--------------- Variant-Specific Implementations ----------------
public HungrySpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
getSpecialData().setRegenerationTime( 40 );
xpReward += 2;
}
/** The damage boost to apply from growth level. */ /** The damage boost to apply from growth level. */
private static final AttributeModifier DAMAGE_BOOST = new AttributeModifier( UUID.fromString( "70457CAB-AA09-4E1C-B44B-99DD4A2A836D" ), private static final AttributeModifier DAMAGE_BOOST = new AttributeModifier( UUID.fromString( "70457CAB-AA09-4E1C-B44B-99DD4A2A836D" ),
"Feeding damage boost", 1.0, AttributeModifier.Operation.ADDITION ); "Feeding damage boost", 1.0, AttributeModifier.Operation.ADDITION );
@ -90,6 +83,13 @@ public class HungrySpiderEntity extends _SpecialSpiderEntity {
/** The level of increased max health gained. */ /** The level of increased max health gained. */
private int maxHealthStacks; private int maxHealthStacks;
public HungrySpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
getSpecialData().setRegenerationTime( 40 );
xpReward += 2;
}
/** Override to change this entity's AI goals. */ /** Override to change this entity's AI goals. */
@Override @Override
protected void registerVariantGoals() { protected void registerVariantGoals() {

View file

@ -74,7 +74,7 @@ public class MotherSpiderEntity extends _SpecialSpiderEntity {
xpReward += 1; xpReward += 1;
babies = 2 + random.nextInt( 3 ); babies = 2 + random.nextInt( 3 );
extraBabies = 2 + random.nextInt( 3 ); extraBabies = 3 + random.nextInt( 4 );
} }
/** The number of babies spawned on death. */ /** The number of babies spawned on death. */

View file

@ -22,8 +22,6 @@ public final class References {
//--------------- ENTITY EVENTS ---------------- //--------------- ENTITY EVENTS ----------------
// Used in World#broadcastEntityEvent(Entity, byte) then executed by Entity#handleEntityEvent(byte) // Used in World#broadcastEntityEvent(Entity, byte) then executed by Entity#handleEntityEvent(byte)
public static final byte EVENT_SHIELD_BLOCK_SOUND = 29;
public static final byte EVENT_SHIELD_BREAK_SOUND = 30;
public static final byte EVENT_TELEPORT_TRAIL_PARTICLES = 46; public static final byte EVENT_TELEPORT_TRAIL_PARTICLES = 46;
@ -60,13 +58,17 @@ public final class References {
public static final String TAG_WATER_DAMAGE = "WaterDamage"; public static final String TAG_WATER_DAMAGE = "WaterDamage";
public static final String TAG_STICKY_IMMUNE = "StickyImmune"; public static final String TAG_STICKY_IMMUNE = "StickyImmune";
public static final String TAG_POTION_IMMUNE = "PotionImmune"; public static final String TAG_POTION_IMMUNE = "PotionImmune";
public static final String TAG_SUPERCHARGED = "Supercharged";
// Creepers // Creepers
public static final String TAG_SUPERCHARGED = "Supercharged";
public static final String TAG_DRY_EXPLODE = "CannotExplodeWhileWet"; public static final String TAG_DRY_EXPLODE = "CannotExplodeWhileWet";
public static final String TAG_WHEN_BURNING_EXPLODE = "ExplodesWhileBurning"; public static final String TAG_WHEN_BURNING_EXPLODE = "ExplodesWhileBurning";
public static final String TAG_WHEN_SHOT_EXPLODE = "ExplodesWhenShot"; public static final String TAG_WHEN_SHOT_EXPLODE = "ExplodesWhenShot";
// Blazes
public static final String TAG_BURST_COUNT = "FireballBurstCount";
public static final String TAG_BURST_DELAY = "FireballBurstDelay";
// Baby-able families - Skeletons, Wither Skeletons // Baby-able families - Skeletons, Wither Skeletons
public static final String TAG_IS_BABY = "IsBaby"; public static final String TAG_IS_BABY = "IsBaby";
@ -75,13 +77,14 @@ public final class References {
public static final String TAG_EXTRA_BABIES = "ExtraBabies"; // Splitting Creeper, Mother (Cave) Spider public static final String TAG_EXTRA_BABIES = "ExtraBabies"; // Splitting Creeper, Mother (Cave) Spider
// Growing mobs // Growing mobs
public static final String TAG_GROWTH_LEVEL = "GrowthLevel"; // Hungry Spider public static final String TAG_GROWTH_LEVEL = "GrowthLevel"; // Hungry Spider, Conflagration Blaze
public static final String TAG_HEALTH_STACKS = "HealthStacks"; // Hungry Spider public static final String TAG_HEALTH_STACKS = "HealthStacks"; // Hungry Spider
// Misc. // Misc.
public static final String TAG_FUSE_TIME = "FuseTime"; // Blackberry Slime, Volatile Magma Cube public static final String TAG_FUSE_TIME = "FuseTime"; // Blackberry Slime, Volatile Magma Cube
public static final String TAG_AMMO = "Ammo"; // Web (Cave) Spider public static final String TAG_AMMO = "Ammo"; // Web (Cave) Spider
public static final String TAG_IS_FAKE = "IsFake"; // Mirage Enderman public static final String TAG_IS_FAKE = "IsFake"; // Mirage Enderman
public static final String TAG_EXPLOSION_POWER = "ExplosionPower"; // Hellfire Blaze
//--------------- INTERNATIONALIZATION ---------------- //--------------- INTERNATIONALIZATION ----------------

View file

@ -19,3 +19,6 @@ protected net.minecraft.entity.monster.CreeperEntity func_190741_do()V # spawnLi
# Endermen # Endermen
protected net.minecraft.entity.monster.EndermanEntity func_70816_c(Lnet/minecraft/entity/Entity;)Z # teleportTowards(Entity) protected net.minecraft.entity.monster.EndermanEntity func_70816_c(Lnet/minecraft/entity/Entity;)Z # teleportTowards(Entity)
protected net.minecraft.entity.monster.EndermanEntity func_70825_j(DDD)Z # teleport(x,y,z) protected net.minecraft.entity.monster.EndermanEntity func_70825_j(DDD)Z # teleport(x,y,z)
# Blazes
public net.minecraft.entity.monster.BlazeEntity func_70844_e(Z)V # setCharged(value)