mirror of
https://github.com/FatherToast/SpecialMobs.git
synced 2025-08-31 14:31:25 +00:00
Merge branch '1.16.5' of https://github.com/FatherToast/SpecialMobs into 1.16.5
This commit is contained in:
commit
c3665d3807
53 changed files with 2813 additions and 157 deletions
|
@ -35,6 +35,7 @@ public class ClientRegister {
|
|||
registerFamilyRenderers( MobFamily.ZOMBIE, SpecialZombieRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.SKELETON, SpecialSkeletonRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.WITHER_SKELETON, SpecialSkeletonRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.SLIME, SpecialSlimeRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.SPIDER, SpecialSpiderRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.CAVE_SPIDER, SpecialSpiderRenderer::new );
|
||||
registerFamilyRenderers( MobFamily.SILVERFISH, SpecialSilverfishRenderer::new );
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package fathertoast.specialmobs.client;
|
||||
|
||||
import fathertoast.specialmobs.common.entity.ai.IAngler;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.FishingRodItem;
|
||||
import net.minecraft.item.IItemPropertyGetter;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Item property getter override that allows the fishing rod item animation to function for any entity implementing IAngler.
|
||||
*/
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class FishingRodItemPropertyGetter implements IItemPropertyGetter {
|
||||
|
||||
@Override
|
||||
public float call( @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity ) {
|
||||
if( entity == null ) return 0.0F;
|
||||
|
||||
boolean inMainHand = entity.getMainHandItem() == stack;
|
||||
boolean inOffhand = entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof FishingRodItem);
|
||||
|
||||
return (inMainHand || inOffhand) && (
|
||||
entity instanceof PlayerEntity && ((PlayerEntity) entity).fishing != null ||
|
||||
entity instanceof IAngler && ((IAngler) entity).isLineOut() // Line added to vanilla logic
|
||||
) ? 1.0F : 0.0F;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package fathertoast.specialmobs.client.renderer.entity;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.SlimeRenderer;
|
||||
import net.minecraft.entity.monster.SlimeEntity;
|
||||
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 SpecialSlimeRenderer extends SlimeRenderer {
|
||||
|
||||
private final float baseShadowRadius;
|
||||
|
||||
public SpecialSlimeRenderer( EntityRendererManager rendererManager ) {
|
||||
super( rendererManager );
|
||||
baseShadowRadius = shadowRadius;
|
||||
addLayer( new SpecialMobEyesLayer<>( this ) );
|
||||
// Model doesn't support size parameter
|
||||
//addLayer( new SpecialMobOverlayLayer<>( this, new SlimeModel<>( 0.25F ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureLocation( SlimeEntity entity ) {
|
||||
return ((ISpecialMob<?>) entity).getSpecialData().getTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void scale( SlimeEntity entity, MatrixStack matrixStack, float partialTick ) {
|
||||
super.scale( entity, matrixStack, partialTick );
|
||||
|
||||
final float scale = ((ISpecialMob<?>) entity).getSpecialData().getRenderScale();
|
||||
shadowRadius = baseShadowRadius * scale * entity.getSize(); // Factor slime size into shadow
|
||||
matrixStack.scale( scale, scale, scale );
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ public class MobFamily<T extends LivingEntity> {
|
|||
|
||||
public static final MobFamily<ZombieEntity> ZOMBIE = new MobFamily<>(
|
||||
"Zombie", "zombies", 0x00AFAF, new EntityType[] { EntityType.ZOMBIE, EntityType.HUSK },
|
||||
/*"Brute", "Fire", "Fishing", "Giant", "Hungry", "Husk",*/ "MadScientist"//, "Plague"
|
||||
"Brute", "Fire", /*"Fishing",*/ "Giant", "Hungry", "Husk", "MadScientist", "Plague"
|
||||
);
|
||||
// public static final MobFamily<ZombieEntity> ZOMBIFIED_PIGLIN = new MobFamily<>(
|
||||
// "ZombifiedPiglin", "zombie pigmen", 0xEA9393, new EntityType[] { EntityType.ZOMBIFIED_PIGLIN },
|
||||
|
@ -61,10 +61,10 @@ public class MobFamily<T extends LivingEntity> {
|
|||
"Brute", "Gatling", "Giant", "Knight", /*"Ninja",*/ "Sniper"//, "Spitfire"
|
||||
);
|
||||
|
||||
// public static final MobFamily<SlimeEntity> SLIME = new MobFamily<>(
|
||||
// "Slime", "slimes", 0x51A03E, new EntityType[] { EntityType.SLIME },
|
||||
// "Blackberry", "Blueberry", "Caramel", "Grape", "Lemon", "Strawberry", "Watermelon"
|
||||
// );
|
||||
public static final MobFamily<SlimeEntity> SLIME = new MobFamily<>(
|
||||
"Slime", "slimes", 0x51A03E, new EntityType[] { EntityType.SLIME },
|
||||
"Blackberry", /*"Blueberry",*/ "Caramel", "Grape", "Lemon", "Strawberry", "Watermelon"
|
||||
);
|
||||
// public static final MobFamily<MagmaCubeEntity> MAGMA_CUBE = new MobFamily<>(
|
||||
// "MagmaCube", "magma cubes", 0x340000, new EntityType[] { EntityType.MAGMA_CUBE },
|
||||
// "Flying", "Hardened", "Sticky", "Volatile"
|
||||
|
|
|
@ -32,17 +32,21 @@ public class SpecialMobs {
|
|||
* o entity replacer
|
||||
* o dimension-sensitive configs
|
||||
* o environment-sensitive configs
|
||||
* ? natural spawning
|
||||
* o entities
|
||||
* - nbt-driven capabilities (special mob data)
|
||||
* o fish hook
|
||||
* o bug projectile
|
||||
* + bestiary
|
||||
* ? configurable stats
|
||||
* - monster families (see doc for specifics)
|
||||
* - creepers
|
||||
* - chance to spawn charged during thunderstorms
|
||||
* + scope
|
||||
* o zombies
|
||||
* - zombies
|
||||
* o villager infection
|
||||
* o ranged attack AI (using bow)
|
||||
* + transformations
|
||||
* - ranged attack AI (using bow)
|
||||
* - use shields
|
||||
* + drowned
|
||||
* o zombified piglins
|
||||
|
@ -51,19 +55,20 @@ public class SpecialMobs {
|
|||
* - skeletons
|
||||
* - use shields
|
||||
* - babies
|
||||
* o wither skeletons
|
||||
* o use shields
|
||||
* o babies
|
||||
* o slimes
|
||||
* o use attack damage attribute
|
||||
* - wither skeletons
|
||||
* - use shields
|
||||
* - babies
|
||||
* - slimes
|
||||
* o smallest size can deal damage
|
||||
* o magma cubes
|
||||
* o use attack damage attribute
|
||||
* o smallest size can deal damage
|
||||
* - spiders
|
||||
* o ranged attack AI
|
||||
* - cave spiders
|
||||
* o ranged attack AI
|
||||
* - silverfish
|
||||
* ? ranged attack AI
|
||||
* + puffer
|
||||
* - endermen
|
||||
* o witches
|
||||
* o ability to equip held items
|
||||
|
@ -87,8 +92,6 @@ public class SpecialMobs {
|
|||
|
||||
/** The path to the textures folder. */
|
||||
public static final String TEXTURE_PATH = "textures/entity/";
|
||||
/** The path to the loot tables folder. */
|
||||
public static final String LOOT_TABLE_PATH = MOD_ID + ":entities/";
|
||||
|
||||
/** Logger instance for the mod. */
|
||||
public static final Logger LOG = LogManager.getLogger( MOD_ID );
|
||||
|
|
|
@ -176,8 +176,8 @@ public final class MobHelper {
|
|||
public static EffectInstance nextPlagueEffect( Random random, World world ) {
|
||||
final int duration = MobHelper.getDebuffDuration( world.getDifficulty() );
|
||||
|
||||
//EffectInstance potion = POTIONS_PLAGUE[random.nextInt( POTIONS_PLAGUE.length - (Config.get().GENERAL.DISABLE_NAUSEA ? 1 : 0) )]; TODO config
|
||||
EffectInstance potion = PLAGUE_EFFECTS[random.nextInt( PLAGUE_EFFECTS.length )];
|
||||
//final EffectInstance potion = PLAGUE_EFFECTS[random.nextInt( PLAGUE_EFFECTS.length - (Config.get().GENERAL.DISABLE_NAUSEA ? 1 : 0) )]; TODO config
|
||||
final EffectInstance potion = PLAGUE_EFFECTS[random.nextInt( PLAGUE_EFFECTS.length )];
|
||||
return new EffectInstance( potion.getEffect(), duration * potion.getDuration(), potion.getAmplifier() );
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ public final class MobHelper {
|
|||
public static EffectInstance nextWitchSpiderEffect( Random random, World world, boolean includePoison ) {
|
||||
final int duration = MobHelper.getDebuffDuration( world.getDifficulty() );
|
||||
|
||||
EffectInstance potion = WITCH_EFFECTS[random.nextInt( WITCH_EFFECTS.length - (includePoison ? 0 : 1) )];
|
||||
final EffectInstance potion = WITCH_EFFECTS[random.nextInt( WITCH_EFFECTS.length - (includePoison ? 0 : 1) )];
|
||||
return new EffectInstance( potion.getEffect(), duration * potion.getDuration(), potion.getAmplifier() );
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.util.ArrayList;
|
|||
*/
|
||||
public final class AIHelper {
|
||||
|
||||
/** Inserts an AI goal at the specified priority. Existing goals have their priority adjusted accordingly. */
|
||||
/** Inserts an AI goal at the specified priority. Existing goals have their priority incremented accordingly. */
|
||||
public static void insertGoal( GoalSelector ai, int priority, Goal goal ) {
|
||||
for( PrioritizedGoal task : new ArrayList<>( ai.availableGoals ) ) {
|
||||
if( task.getPriority() >= priority ) task.priority++;
|
||||
|
@ -19,6 +19,14 @@ public final class AIHelper {
|
|||
ai.addGoal( priority, goal );
|
||||
}
|
||||
|
||||
/** Inserts an AI goal at the specified priority. Existing goals have their priority decremented accordingly. */
|
||||
public static void insertGoalReverse( GoalSelector ai, int priority, Goal goal ) {
|
||||
for( PrioritizedGoal task : new ArrayList<>( ai.availableGoals ) ) {
|
||||
if( task.getPriority() <= priority ) task.priority--;
|
||||
}
|
||||
ai.addGoal( priority, goal );
|
||||
}
|
||||
|
||||
/** Removes all goals with the specified priority. */
|
||||
public static void removeGoals( GoalSelector ai, int priority ) {
|
||||
for( PrioritizedGoal task : new ArrayList<>( ai.availableGoals ) ) {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package fathertoast.specialmobs.common.entity.ai;
|
||||
|
||||
/**
|
||||
* Monsters must implement this interface to shoot fish hooks.
|
||||
* This allows get and set methods for the fish hook so that the server can communicate rendering info to the client.
|
||||
*/
|
||||
public interface IAngler {
|
||||
|
||||
/** Sets this angler's line as out (or in). */
|
||||
void setLineOut( boolean value );
|
||||
|
||||
/** @return Whether this angler's line is out. */
|
||||
boolean isLineOut();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package fathertoast.specialmobs.common.entity.ai;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Monsters must implement this interface to use the ninja goal AI.
|
||||
* This allows get and set methods for the disguise block and immobile state.
|
||||
*/
|
||||
public interface INinja {
|
||||
|
||||
/** @return Whether this ninja is currently immobile. */
|
||||
boolean isImmobile();
|
||||
|
||||
/** Sets this ninja's immovable state. When activated, the entity is 'snapped' to the nearest block position. */
|
||||
void setImmobile( boolean value );
|
||||
|
||||
/** @return The block being hidden (rendered) as, or null if not hiding. */
|
||||
@Nullable
|
||||
BlockState getDisguiseBlock();
|
||||
|
||||
/** Sets the block being hidden (rendered) as, set to null to cancel hiding. */
|
||||
void setDisguiseBlock( @Nullable BlockState block );
|
||||
}
|
|
@ -12,11 +12,13 @@ import net.minecraft.entity.LivingEntity;
|
|||
import net.minecraft.entity.SpawnReason;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.entity.monster.SlimeEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -32,6 +34,7 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 0.6F );
|
||||
return new BestiaryInfo( 0xB300B3 );
|
||||
}
|
||||
|
||||
|
@ -59,6 +62,7 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Constructor
|
||||
public MotherCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.8F );
|
||||
getSpecialData().setRegenerationTime( 30 );
|
||||
xpReward += 1;
|
||||
|
||||
|
@ -88,16 +92,18 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
if( extraBabies > 0 && amount > 1.0F && level instanceof IServerWorld && random.nextFloat() < 0.33F ) {
|
||||
extraBabies--;
|
||||
spawnBaby( 0.66F, null );
|
||||
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity while it's dead. */
|
||||
/** Called to remove this entity from the world. Includes death, unloading, interdimensional travel, etc. */
|
||||
@Override
|
||||
protected void tickDeath() {
|
||||
if( deathTime == 19 && level instanceof IServerWorld ) { // At 19, the entity will be immediately removed upon call to super method
|
||||
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;
|
||||
|
@ -106,8 +112,7 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
}
|
||||
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
|
||||
}
|
||||
|
||||
super.tickDeath();
|
||||
super.remove( keepData );
|
||||
}
|
||||
|
||||
/** Helper method to simplify spawning babies. */
|
||||
|
|
|
@ -60,7 +60,7 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,14 +82,11 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -166,12 +163,12 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
/** @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 0.65F * getSpecialData().getBaseScale() * (isBaby() ? 0.53448F : 1.0F); // Use base spider scale instead of super
|
||||
}
|
||||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -186,7 +183,7 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -26,6 +26,7 @@ public class DeathCreeperEntity extends _SpecialCreeperEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.6F );
|
||||
return new BestiaryInfo( 0xCD0000 );
|
||||
}
|
||||
|
||||
|
@ -52,6 +53,7 @@ public class DeathCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Constructor
|
||||
public DeathCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
setExplodesWhileBurning( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.7F, 1.99F );
|
||||
return new BestiaryInfo( 0x5F9D22, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
|
@ -57,6 +58,7 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Constructor
|
||||
public SplittingCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
getSpecialData().setImmuneToBurning( true );
|
||||
setExplodesWhenShot( true );
|
||||
xpReward += 2;
|
||||
|
|
|
@ -66,7 +66,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,14 +82,11 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -293,15 +290,15 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
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 The eye height of this entity when standing. */ - Creepers use auto-scaled eye height
|
||||
// @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 specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -316,7 +313,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -10,9 +10,11 @@ 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.effect.LightningBoltEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
|
@ -67,6 +69,10 @@ public class LightningEndermanEntity extends _SpecialEndermanEntity {
|
|||
}
|
||||
}
|
||||
|
||||
/** Called when this entity is struck by lightning. */
|
||||
@Override
|
||||
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "lightning" ),
|
||||
GET_TEXTURE_PATH( "lightning_eyes" )
|
||||
|
|
|
@ -23,7 +23,7 @@ public class MiniEndermanEntity extends _SpecialEndermanEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.5F, 0.9F );
|
||||
entityType.sized( 0.5F, 0.99F );
|
||||
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
}
|
||||
|
||||
|
@ -75,14 +75,11 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -164,7 +161,7 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -179,7 +176,7 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package fathertoast.specialmobs.common.entity.projectile;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class BugSpitEntity extends Entity {
|
||||
|
||||
public BugSpitEntity( EntityType<? extends BugSpitEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package fathertoast.specialmobs.common.entity.projectile;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class SpecialFishHookEntity extends Entity {
|
||||
|
||||
public SpecialFishHookEntity( EntityType<? extends SpecialFishHookEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package fathertoast.specialmobs.common.entity.silverfish;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.IAngler;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootEntryItemBuilder;
|
||||
import fathertoast.specialmobs.datagen.loot.LootPoolBuilder;
|
||||
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.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class FishingSilverfishEntity extends _SpecialSilverfishEntity implements IAngler {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.5F, 0.4F );
|
||||
return new BestiaryInfo( 0x2D41F4 );
|
||||
//TODO theme - fishing
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialSilverfishEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 4.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.9 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Fishing Silverfish",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addPool( new LootPoolBuilder( "common" )
|
||||
.addEntry( new LootEntryItemBuilder( Items.COD ).setCount( 0, 2 ).addLootingBonus( 0, 1 ).smeltIfBurning().toLootEntry() )
|
||||
.toLootPool() );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public FishingSilverfishEntity( EntityType<? extends _SpecialSilverfishEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
getSpecialData().setCanBreatheInWater( true );
|
||||
getSpecialData().setIgnoreWaterPush( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackSpread = 10.0F;
|
||||
getSpecialData().rangedAttackCooldown = 32;
|
||||
getSpecialData().rangedAttackMaxCooldown = 48;
|
||||
getSpecialData().rangedAttackMaxRange = 10.0F;
|
||||
|
||||
//TODO add angler AI @ 4
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "fishing" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- IAngler Implementations ----------------
|
||||
|
||||
/** Sets this angler's line as out (or in). */
|
||||
@Override
|
||||
public void setLineOut( boolean value ) { }
|
||||
|
||||
/** @return Whether this angler's line is out. */
|
||||
@Override
|
||||
public boolean isLineOut() { return false; }
|
||||
}
|
|
@ -25,7 +25,7 @@ public class ToughSilverfishEntity extends _SpecialSilverfishEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.6F, 0.9F );
|
||||
entityType.sized( 0.6F, 0.45F );
|
||||
return new BestiaryInfo( 0xDD0E0E, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class _SpecialSilverfishEntity extends SilverfishEntity implements ISpeci
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialSilverfishEntity( EntityType<? extends _SpecialSilverfishEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,14 +84,11 @@ public class _SpecialSilverfishEntity extends SilverfishEntity implements ISpeci
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -191,7 +188,7 @@ public class _SpecialSilverfishEntity extends SilverfishEntity implements ISpeci
|
|||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -206,7 +203,7 @@ public class _SpecialSilverfishEntity extends SilverfishEntity implements ISpeci
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -32,6 +32,7 @@ public class BruteSkeletonEntity extends _SpecialSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.7F, 2.4F );
|
||||
return new BestiaryInfo( 0xFFF87E );
|
||||
}
|
||||
|
||||
|
@ -59,6 +60,7 @@ public class BruteSkeletonEntity extends _SpecialSkeletonEntity {
|
|||
@SpecialMob.Constructor
|
||||
public BruteSkeletonEntity( EntityType<? extends _SpecialSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public class GiantSkeletonEntity extends _SpecialSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.7F );
|
||||
entityType.sized( 0.9F, 2.99F );
|
||||
return new BestiaryInfo( 0x494949 );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
package fathertoast.specialmobs.common.entity.skeleton;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.INinja;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
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.player.PlayerEntity;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Optional;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class NinjaSkeletonEntity extends _SpecialSkeletonEntity implements INinja {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x333366 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialSkeletonEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Skeleton Ninja",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addUncommonDrop( "uncommon", Blocks.INFESTED_STONE, Blocks.INFESTED_COBBLESTONE, Blocks.INFESTED_STONE_BRICKS,
|
||||
Blocks.INFESTED_CRACKED_STONE_BRICKS, Blocks.INFESTED_MOSSY_STONE_BRICKS, Blocks.INFESTED_CHISELED_STONE_BRICKS );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public NinjaSkeletonEntity( EntityType<? extends _SpecialSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
setRangedAI( 1.0, 10, 9.0F );
|
||||
|
||||
//TODO AIHelper.insertGoalReverse( goalSelector, getVariantAttackPriority() - 1, null );
|
||||
}
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
setCanPickUpLoot( true );
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a melee weapon. */
|
||||
@Override
|
||||
protected double getVariantMeleeChance() { return 0.5; }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
revealTo( target );
|
||||
}
|
||||
|
||||
/** @return Attempts to damage this entity; returns true if the hit was successful. */
|
||||
@Override
|
||||
public boolean hurt( DamageSource source, float amount ) {
|
||||
if( super.hurt( source, amount ) ) {
|
||||
revealTo( source.getEntity() );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return Interacts (right click) with this entity and returns the result. */
|
||||
@Override
|
||||
public ActionResultType mobInteract( PlayerEntity player, Hand hand ) {
|
||||
// Attack if the player tries to right click the "block"
|
||||
if( !level.isClientSide() && getDisguiseBlock() != null ) revealTo( player );
|
||||
return super.mobInteract( player, hand );
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
@Override
|
||||
public void tick() {
|
||||
// TODO can this be moved to the ninja AI?
|
||||
if( !level.isClientSide() ) {
|
||||
if( canHide ) {
|
||||
//EntityAINinja.startHiding( this ); TODO
|
||||
}
|
||||
else if( onGround && getDisguiseBlock() == null &&
|
||||
(getTarget() == null || getTarget() instanceof PlayerEntity && ((PlayerEntity) getTarget()).isCreative()) ) {
|
||||
canHide = true;
|
||||
}
|
||||
}
|
||||
super.tick();
|
||||
}
|
||||
|
||||
// // Moves this entity.
|
||||
// @Override TODO
|
||||
// public void move( MoverType type, double x, double y, double z ) {
|
||||
// if( isImmobile() && type != MoverType.PISTON ) {
|
||||
// motionY = 0.0;
|
||||
// }
|
||||
// else {
|
||||
// super.move( type, x, y, z );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Returns true if this entity should push and be pushed by other entities when colliding.
|
||||
// @Override
|
||||
// public boolean canBePushed() { return !isImmobile(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
public void setRemainingFireTicks( int ticks ) {
|
||||
if( !isImmobile() ) super.setRemainingFireTicks( ticks );
|
||||
}
|
||||
|
||||
/** Reveals this ninja and sets its target so that it doesn't immediately re-disguise itself. */
|
||||
public void revealTo( @Nullable Entity target ) {
|
||||
setDisguiseBlock( null );
|
||||
if( target instanceof LivingEntity ) setTarget( (LivingEntity) target );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/skeleton/skeleton.png" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "ninja_overlay" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- INinja Implementations ----------------
|
||||
|
||||
/** The parameter for the ninja immobile state. */
|
||||
private static final DataParameter<Boolean> IS_HIDING = EntityDataManager.defineId( NinjaSkeletonEntity.class, DataSerializers.BOOLEAN );
|
||||
/** The parameter for the ninja disguise block. */
|
||||
private static final DataParameter<Optional<BlockState>> HIDING_BLOCK = EntityDataManager.defineId( NinjaSkeletonEntity.class, DataSerializers.BLOCK_STATE );
|
||||
|
||||
private boolean canHide = true;
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
entityData.define( IS_HIDING, false );
|
||||
entityData.define( HIDING_BLOCK, Optional.empty() );
|
||||
}
|
||||
|
||||
/** @return Whether this ninja is currently immobile. */
|
||||
@Override
|
||||
public boolean isImmobile() { return getEntityData().get( IS_HIDING ); }
|
||||
|
||||
/** Sets this ninja's immovable state. When activated, the entity is 'snapped' to the nearest block position. */
|
||||
@Override
|
||||
public void setImmobile( boolean value ) {
|
||||
if( value != isImmobile() ) {
|
||||
getEntityData().set( IS_HIDING, value );
|
||||
if( value ) {
|
||||
clearFire();
|
||||
moveTo( Math.floor( getX() ) + 0.5, Math.floor( getY() ), Math.floor( getZ() ) + 0.5 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The block being hidden (rendered) as, or null if not hiding. */
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getDisguiseBlock() {
|
||||
if( isAlive() ) return getEntityData().get( HIDING_BLOCK ).orElse( null );
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Sets the block being hidden (rendered) as, set to null to cancel hiding. */
|
||||
@Override
|
||||
public void setDisguiseBlock( @Nullable BlockState block ) {
|
||||
getEntityData().set( HIDING_BLOCK, Optional.ofNullable( block ) );
|
||||
canHide = false;
|
||||
|
||||
// Smoke puff when emerging from disguise
|
||||
if( block == null ) {
|
||||
//spawnExplosionParticle(); TODO
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ public class SpitfireSkeletonEntity extends _SpecialSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.7F ).fireImmune();
|
||||
entityType.sized( 0.9F, 2.99F ).fireImmune();
|
||||
return new BestiaryInfo( 0xDC1A00, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - fire
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialSkeletonEntity( EntityType<? extends _SpecialSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -164,14 +164,11 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
|
|||
return arrow;
|
||||
}
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -209,7 +206,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
|
|||
return groupData;
|
||||
}
|
||||
|
||||
/** Called to change */
|
||||
/** Called to set this entity's attack AI based on current equipment. */
|
||||
@Override
|
||||
public void reassessWeaponGoal() {
|
||||
if( level != null && !level.isClientSide ) {
|
||||
|
@ -358,7 +355,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
|
|||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -373,7 +370,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.AreaEffectCloudEntity;
|
||||
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.ai.goal.Goal;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class BlackberrySlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x331133 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Blackberry Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.GUNPOWDER );
|
||||
loot.addUncommonDrop( "uncommon", Items.BLACK_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public BlackberrySlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
private static final byte MAX_FUSE = 30;
|
||||
|
||||
private int fuse = 0;
|
||||
private int swellDir = 0;
|
||||
private boolean ignited = false;
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 2.0 * size );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SMOKE; }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
goalSelector.addGoal( 0, new SlimeSwellGoal( this ) );
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
@Override
|
||||
public void tick() {
|
||||
if( isAlive() && !level.isClientSide() ) {
|
||||
if( ignited ) swellDir = 1;
|
||||
|
||||
if( swellDir > 0 ) {
|
||||
if( fuse == 0 ) {
|
||||
playSound( SoundEvents.CREEPER_PRIMED, 1.0F, 0.5F );
|
||||
}
|
||||
else if( fuse >= MAX_FUSE ) {
|
||||
dead = true;
|
||||
ExplosionHelper.explode( this, getSize() + 0.5F, true, false );
|
||||
remove();
|
||||
spawnLingeringCloud();
|
||||
}
|
||||
else {
|
||||
changeFuse( +1 );
|
||||
}
|
||||
}
|
||||
else if( swellDir < 0 && fuse > 0 ) {
|
||||
changeFuse( -1 );
|
||||
if( fuse <= 0 ) swellDir = 0;
|
||||
}
|
||||
}
|
||||
super.tick();
|
||||
}
|
||||
|
||||
/** Changes the fuse by a specific amount. The fuse must always be changed in step with render scale, so they stay in sync. */
|
||||
private void changeFuse( int change ) {
|
||||
fuse += change;
|
||||
getSpecialData().setRenderScale( getSpecialData().getRenderScale() + change * 0.014F );
|
||||
}
|
||||
|
||||
/** Called to create a lingering effect cloud as part of this slime's explosion 'attack'. */
|
||||
protected void spawnLingeringCloud() {
|
||||
final List<EffectInstance> effects = new ArrayList<>( getActiveEffects() );
|
||||
|
||||
if( !effects.isEmpty() ) {
|
||||
final AreaEffectCloudEntity potionCloud = new AreaEffectCloudEntity( level, getX(), getY(), getZ() );
|
||||
potionCloud.setRadius( getSize() + 0.5F );
|
||||
potionCloud.setRadiusOnUse( -0.5F );
|
||||
potionCloud.setWaitTime( 10 );
|
||||
potionCloud.setDuration( potionCloud.getDuration() / 2 );
|
||||
potionCloud.setRadiusPerTick( -potionCloud.getRadius() / (float) potionCloud.getDuration() );
|
||||
for( EffectInstance effect : effects ) {
|
||||
potionCloud.addEffect( new EffectInstance( effect ) );
|
||||
}
|
||||
level.addFreshEntity( potionCloud );
|
||||
}
|
||||
}
|
||||
|
||||
/** @return This entity's max fall distance. */
|
||||
@Override
|
||||
public int getMaxFallDistance() { return getTarget() == null ? 3 : 3 + (int) (getHealth() - 1.0F); }
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
@Override
|
||||
public boolean causeFallDamage( float distance, float damageMultiplier ) {
|
||||
final boolean success = super.causeFallDamage( distance, damageMultiplier );
|
||||
|
||||
// Speed up fuse from falling like creepers
|
||||
changeFuse( (int) (distance * 1.5F) );
|
||||
if( fuse > MAX_FUSE - 5 ) changeFuse( MAX_FUSE - 5 - fuse );
|
||||
return success;
|
||||
}
|
||||
|
||||
/** @return Interacts (right click) with this entity and returns the result. */
|
||||
@Override
|
||||
public ActionResultType mobInteract( PlayerEntity player, Hand hand ) {
|
||||
final ItemStack item = player.getItemInHand( hand );
|
||||
if( item.getItem() == Items.FLINT_AND_STEEL ) {
|
||||
// Allow players to ignite blackberry slimes like creepers
|
||||
level.playSound( player, getX(), getY(), getZ(), SoundEvents.FLINTANDSTEEL_USE, getSoundSource(),
|
||||
1.0F, random.nextFloat() * 0.4F + 0.8F );
|
||||
if( !level.isClientSide ) {
|
||||
ignited = true;
|
||||
item.hurtAndBreak( 1, player, ( entity ) -> entity.broadcastBreakEvent( hand ) );
|
||||
}
|
||||
return ActionResultType.sidedSuccess( level.isClientSide );
|
||||
}
|
||||
return super.mobInteract( player, hand );
|
||||
}
|
||||
|
||||
/** Override to save data to this entity's NBT data. */
|
||||
@Override
|
||||
public void addVariantSaveData( CompoundNBT saveTag ) {
|
||||
saveTag.putByte( References.TAG_FUSE_TIME, (byte) fuse );
|
||||
}
|
||||
|
||||
/** Override to load data from this entity's NBT data. */
|
||||
@Override
|
||||
public void readVariantSaveData( CompoundNBT saveTag ) {
|
||||
if( saveTag.contains( References.TAG_FUSE_TIME, References.NBT_TYPE_NUMERICAL ) )
|
||||
fuse = saveTag.getByte( References.TAG_FUSE_TIME );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "blackberry" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- Nested Classes ----------------
|
||||
|
||||
/** The "creeper swell" goal repurposed for use on a slime. */
|
||||
private static class SlimeSwellGoal extends Goal {
|
||||
|
||||
private final BlackberrySlimeEntity slime;
|
||||
|
||||
private LivingEntity target;
|
||||
|
||||
public SlimeSwellGoal( BlackberrySlimeEntity entity ) {
|
||||
slime = entity;
|
||||
setFlags( EnumSet.of( Flag.MOVE ) );
|
||||
}
|
||||
|
||||
public boolean canUse() {
|
||||
final LivingEntity target = slime.getTarget();
|
||||
return slime.swellDir > 0 || target != null && slime.distanceToSqr( target ) < 9.0F + (slime.getSize() - 1) * 2.0F;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
slime.getNavigation().stop();
|
||||
target = slime.getTarget();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
slime.swellDir = -1;
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if( target == null || slime.distanceToSqr( target ) > 49.0 || !slime.getSensing().canSee( target ) ) {
|
||||
slime.swellDir = -1;
|
||||
}
|
||||
else {
|
||||
slime.swellDir = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
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.item.Items;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class BlueberrySlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x766BBC );
|
||||
//TODO theme - water
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Blueberry Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addRareDrop( "rare", Items.GOLD_NUGGET, Items.PRISMARINE_SHARD, Items.PRISMARINE_CRYSTALS );
|
||||
loot.addUncommonDrop( "uncommon", Items.BLUE_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public BlueberrySlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToBurning( true );
|
||||
getSpecialData().setCanBreatheInWater( true );
|
||||
slimeExperienceValue += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.ATTACK_DAMAGE, 1.0 * size );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected boolean isAffectedByFluids() { return false; } // TODO figure out the right way to do this
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "blueberry" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
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.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.List;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class CaramelSlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x9D733F );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Caramel Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.SUGAR );
|
||||
loot.addUncommonDrop( "uncommon", Items.ORANGE_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public CaramelSlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
private final DamageSource grabDamageSource = DamageSource.mobAttack( this ).bypassArmor().bypassMagic();
|
||||
|
||||
private int grabTime;
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 4.0 * size );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; } //TODO
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( grabTime <= -20 && getPassengers().isEmpty() ) {
|
||||
if( target.startRiding( this, true ) ) grabTime = 20;
|
||||
}
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
grabTime--;
|
||||
final List<Entity> riders = getPassengers();
|
||||
if( grabTime <= 0 && !riders.isEmpty() ) {
|
||||
for( Entity rider : riders ) {
|
||||
if( rider instanceof LivingEntity ) {
|
||||
rider.hurt( grabDamageSource, 1.0F );
|
||||
grabTime = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "caramel" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.SpecialLeapAtTargetGoal;
|
||||
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.item.Items;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class GrapeSlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xB333B3 );
|
||||
//TODO theme - mountain
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Grape Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addGuaranteedDrop( "base", Items.SLIME_BALL, 1 );
|
||||
loot.addUncommonDrop( "uncommon", Items.PURPLE_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public GrapeSlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setFallDamageMultiplier( 0.0F );
|
||||
slimeExperienceValue += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 4.0 * size );
|
||||
multAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
goalSelector.addGoal( 0, new SpecialLeapAtTargetGoal(
|
||||
this, 10, 6.0F, 12.0F, 1.1F, 2.6F ) );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; } //TODO
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "grape" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
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.entity.effect.LightningBoltEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class LemonSlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0xE6E861 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Lemon Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.REDSTONE, 1 );
|
||||
loot.addUncommonDrop( "uncommon", Items.YELLOW_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public LemonSlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToFire( true );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 2.0 * size );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; } //TODO
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( target instanceof LivingEntity ) {
|
||||
ExplosionHelper.spawnLightning( level, target.getX(), target.getY(), target.getZ() );
|
||||
|
||||
// Knock self back
|
||||
final float forwardPower = 1.1F;
|
||||
final float upwardPower = 1.0F;
|
||||
final Vector3d vKnockback = new Vector3d( target.getX() - getX(), 0.0, target.getZ() - getZ() )
|
||||
.normalize().scale( -forwardPower ).add( getDeltaMovement().scale( 0.2F ) );
|
||||
setDeltaMovement( vKnockback.x, 0.4 * upwardPower, vKnockback.z );
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when this entity is struck by lightning. */
|
||||
@Override
|
||||
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "lemon" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.SpecialLeapAtTargetGoal;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
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.entity.effect.LightningBoltEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class StrawberrySlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0xBE696B );
|
||||
//TODO theme - fire
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Strawberry Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.FIRE_CHARGE, 1 );
|
||||
loot.addUncommonDrop( "uncommon", Items.RED_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public StrawberrySlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToFire( true );
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
slimeExperienceValue += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; } //TODO
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
target.setSecondsOnFire( getSize() * 3 );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "strawberry" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.SpecialLeapAtTargetGoal;
|
||||
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.particles.IParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class WatermelonSlimeEntity extends _SpecialSlimeEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 3.06F, 3.06F );
|
||||
return new BestiaryInfo( 0xDF7679, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialSlimeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Watermelon Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.MELON_SLICE );
|
||||
loot.addRareDrop( "rare", Items.GLISTERING_MELON_SLICE );
|
||||
loot.addUncommonDrop( "uncommon", Items.PINK_DYE, Items.LIME_DYE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public WatermelonSlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 2.0 * size + 8.0 );
|
||||
setAttribute( Attributes.ARMOR, 15.0 );
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
goalSelector.addGoal( 0, new SpecialLeapAtTargetGoal(
|
||||
this, 10, 0.0F, 5.0F, 1.16F, 1.0F ) );
|
||||
}
|
||||
|
||||
/** @return This slime's particle type for jump effects. */
|
||||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SPLASH; } //TODO
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( target instanceof LivingEntity ) {
|
||||
final float forwardPower = 0.8F;
|
||||
final float upwardPower = 0.5F;
|
||||
final Vector3d vKnockback = new Vector3d( target.getX() - getX(), 0.0, target.getZ() - getZ() )
|
||||
.normalize().scale( forwardPower ).add( getDeltaMovement().scale( 0.2F ) );
|
||||
target.setDeltaMovement( vKnockback.x, 0.4 * upwardPower, vKnockback.z );
|
||||
target.hurtMarked = true;
|
||||
|
||||
setDeltaMovement( getDeltaMovement().multiply( 0.2, 1.0, 0.2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "watermelon" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
package fathertoast.specialmobs.common.entity.slime;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.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.Attribute;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance;
|
||||
import net.minecraft.entity.monster.MonsterEntity;
|
||||
import net.minecraft.entity.monster.SlimeEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
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.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 _SpecialSlimeEntity extends SlimeEntity implements ISpecialMob<_SpecialSlimeEntity> {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x51A03E );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return MonsterEntity.createMonsterAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Slime",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void addBaseLoot( LootTableBuilder loot ) {
|
||||
loot.addLootTable( "main", EntityType.SLIME.getDefaultLootTable() );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public _SpecialSlimeEntity( EntityType<? extends _SpecialSlimeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
protected void modifyVariantAttributes( int size ) { }
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
super.registerGoals();
|
||||
registerVariantGoals();
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** 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( _SpecialSlimeEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
protected int slimeExperienceValue = 0;
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
|
||||
}
|
||||
|
||||
/** Returns true if this slime can deal damage. */
|
||||
@Override
|
||||
protected boolean isDealsDamage() { return getSize() > 0 && isEffectiveAi(); } // TODO config for allow tiny slimes to hit
|
||||
|
||||
/** Sets this slime's size, optionally resetting its health to max. */
|
||||
@Override
|
||||
protected void setSize( int size, boolean resetHealth ) {
|
||||
super.setSize( size, resetHealth );
|
||||
|
||||
modifyVariantAttributes( size );
|
||||
if( resetHealth ) setHealth( getMaxHealth() );
|
||||
xpReward = size + slimeExperienceValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters this slime's base attribute by adding an amount to it.
|
||||
* Do NOT use this for move speed, instead use {@link #multAttribute(Attribute, double)}
|
||||
*/
|
||||
protected void addAttribute( Attribute attribute, double amount ) {
|
||||
if( attribute != Attributes.MAX_HEALTH && attribute != Attributes.ATTACK_DAMAGE && attribute != Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Slime relative attributes are only health, damage, and speed!" );
|
||||
|
||||
final ModifiableAttributeInstance attributeInstance = getAttribute( attribute );
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + attribute.getDescriptionId() );
|
||||
attributeInstance.setBaseValue( attributeInstance.getBaseValue() + amount );
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters this slime's base attribute by multiplying it by an amount.
|
||||
* Mainly use this for move speed, for other attributes use {@link #addAttribute(Attribute, double)}
|
||||
*/
|
||||
protected void multAttribute( Attribute attribute, double amount ) {
|
||||
if( attribute != Attributes.MAX_HEALTH && attribute != Attributes.ATTACK_DAMAGE && attribute != Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Slime relative attributes are only health, damage, and speed!" );
|
||||
|
||||
final ModifiableAttributeInstance attributeInstance = getAttribute( attribute );
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + attribute.getDescriptionId() );
|
||||
attributeInstance.setBaseValue( attributeInstance.getBaseValue() * amount );
|
||||
}
|
||||
|
||||
/** Sets this slime's base attribute. */
|
||||
protected void setAttribute( Attribute attribute, double amount ) {
|
||||
if( attribute == Attributes.MAX_HEALTH || attribute == Attributes.ATTACK_DAMAGE || attribute == Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Use slime relative attribute!" );
|
||||
|
||||
final ModifiableAttributeInstance attributeInstance = getAttribute( attribute );
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + attribute.getDescriptionId() );
|
||||
attributeInstance.setBaseValue( amount );
|
||||
}
|
||||
|
||||
/** 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<_SpecialSlimeEntity> specialData;
|
||||
|
||||
/** @return This mob's special data. */
|
||||
@Override
|
||||
public SpecialMobData<_SpecialSlimeEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final int getExperience() { return slimeExperienceValue; } // Slime base xp
|
||||
|
||||
/** Sets the experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final void setExperience( int xp ) {
|
||||
slimeExperienceValue = xp;
|
||||
xpReward = getSize() + xp;
|
||||
}
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "slime/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/slime/slime.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( isSensitiveToWater() && source.getDirectEntity() instanceof SnowballEntity ) {
|
||||
amount = Math.max( 3.0F, amount );
|
||||
}
|
||||
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 );
|
||||
|
||||
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 );
|
||||
|
||||
getSpecialData().readFromNBT( saveTag );
|
||||
readVariantSaveData( saveTag );
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ public class DesertSpiderEntity extends _SpecialSpiderEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.95F, 0.8F );
|
||||
entityType.sized( 0.95F, 0.7F );
|
||||
return new BestiaryInfo( 0xE6DDAC );
|
||||
//TODO theme - desert
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class MotherSpiderEntity extends _SpecialSpiderEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 1.8F, 1.2F );
|
||||
entityType.sized( 1.7F, 1.0F );
|
||||
return new BestiaryInfo( 0xB300B3 );
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class MotherSpiderEntity extends _SpecialSpiderEntity {
|
|||
@SpecialMob.Constructor
|
||||
public MotherSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.4F );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
getSpecialData().setRegenerationTime( 30 );
|
||||
xpReward += 1;
|
||||
|
||||
|
@ -90,16 +90,18 @@ public class MotherSpiderEntity extends _SpecialSpiderEntity {
|
|||
if( extraBabies > 0 && amount > 1.0F && level instanceof IServerWorld && random.nextFloat() < 0.33F ) {
|
||||
extraBabies--;
|
||||
spawnBaby( 0.66F, null );
|
||||
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity while it's dead. */
|
||||
/** Called to remove this entity from the world. Includes death, unloading, interdimensional travel, etc. */
|
||||
@Override
|
||||
protected void tickDeath() {
|
||||
if( deathTime == 19 && level instanceof IServerWorld ) { // At 19, the entity will be immediately removed upon call to super method
|
||||
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;
|
||||
|
@ -108,8 +110,7 @@ public class MotherSpiderEntity extends _SpecialSpiderEntity {
|
|||
}
|
||||
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
|
||||
}
|
||||
|
||||
super.tickDeath();
|
||||
super.remove( keepData );
|
||||
}
|
||||
|
||||
/** Helper method to simplify spawning babies. */
|
||||
|
|
|
@ -60,7 +60,7 @@ public class _SpecialSpiderEntity extends SpiderEntity implements ISpecialMob<_S
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,14 +82,11 @@ public class _SpecialSpiderEntity extends SpiderEntity implements ISpecialMob<_S
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -171,7 +168,7 @@ public class _SpecialSpiderEntity extends SpiderEntity implements ISpecialMob<_S
|
|||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -186,7 +183,7 @@ public class _SpecialSpiderEntity extends SpiderEntity implements ISpecialMob<_S
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -32,6 +32,7 @@ public class BruteWitherSkeletonEntity extends _SpecialWitherSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.85F, 2.9F );
|
||||
return new BestiaryInfo( 0xFFF87E );
|
||||
}
|
||||
|
||||
|
@ -59,6 +60,7 @@ public class BruteWitherSkeletonEntity extends _SpecialWitherSkeletonEntity {
|
|||
@SpecialMob.Constructor
|
||||
public BruteWitherSkeletonEntity( EntityType<? extends _SpecialWitherSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.44F );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public class GiantWitherSkeletonEntity extends _SpecialWitherSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.95F, 3.24F );
|
||||
entityType.sized( 0.95F, 3.6F );
|
||||
return new BestiaryInfo( 0x474D4D );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
package fathertoast.specialmobs.common.entity.witherskeleton;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.INinja;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
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.player.PlayerEntity;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.Optional;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class NinjaWitherSkeletonEntity extends _SpecialWitherSkeletonEntity implements INinja {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x333366 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialWitherSkeletonEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Wither Skeleton Ninja",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addUncommonDrop( "uncommon", Blocks.INFESTED_STONE, Blocks.INFESTED_COBBLESTONE, Blocks.INFESTED_STONE_BRICKS,
|
||||
Blocks.INFESTED_CRACKED_STONE_BRICKS, Blocks.INFESTED_MOSSY_STONE_BRICKS, Blocks.INFESTED_CHISELED_STONE_BRICKS );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public NinjaWitherSkeletonEntity( EntityType<? extends _SpecialWitherSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
setRangedAI( 1.0, 10, 9.0F );
|
||||
|
||||
//TODO AIHelper.insertGoalReverse( goalSelector, getVariantAttackPriority() - 1, null );
|
||||
}
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
setCanPickUpLoot( true );
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a bow. */
|
||||
@Override
|
||||
protected double getVariantBowChance() { return 0.5; }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
revealTo( target );
|
||||
}
|
||||
|
||||
/** @return Attempts to damage this entity; returns true if the hit was successful. */
|
||||
@Override
|
||||
public boolean hurt( DamageSource source, float amount ) {
|
||||
if( super.hurt( source, amount ) ) {
|
||||
revealTo( source.getEntity() );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @return Interacts (right click) with this entity and returns the result. */
|
||||
@Override
|
||||
public ActionResultType mobInteract( PlayerEntity player, Hand hand ) {
|
||||
// Attack if the player tries to right click the "block"
|
||||
if( !level.isClientSide() && getDisguiseBlock() != null ) revealTo( player );
|
||||
return super.mobInteract( player, hand );
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
@Override
|
||||
public void tick() {
|
||||
// TODO can this be moved to the ninja AI?
|
||||
if( !level.isClientSide() ) {
|
||||
if( canHide ) {
|
||||
//EntityAINinja.startHiding( this ); TODO
|
||||
}
|
||||
else if( onGround && getDisguiseBlock() == null &&
|
||||
(getTarget() == null || getTarget() instanceof PlayerEntity && ((PlayerEntity) getTarget()).isCreative()) ) {
|
||||
canHide = true;
|
||||
}
|
||||
}
|
||||
super.tick();
|
||||
}
|
||||
|
||||
// // Moves this entity.
|
||||
// @Override TODO
|
||||
// public void move( MoverType type, double x, double y, double z ) {
|
||||
// if( isImmobile() && type != MoverType.PISTON ) {
|
||||
// motionY = 0.0;
|
||||
// }
|
||||
// else {
|
||||
// super.move( type, x, y, z );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Returns true if this entity should push and be pushed by other entities when colliding.
|
||||
// @Override
|
||||
// public boolean canBePushed() { return !isImmobile(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
public void setRemainingFireTicks( int ticks ) {
|
||||
if( !isImmobile() ) super.setRemainingFireTicks( ticks );
|
||||
}
|
||||
|
||||
/** Reveals this ninja and sets its target so that it doesn't immediately re-disguise itself. */
|
||||
public void revealTo( @Nullable Entity target ) {
|
||||
setDisguiseBlock( null );
|
||||
if( target instanceof LivingEntity ) setTarget( (LivingEntity) target );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/skeleton/skeleton.png" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "ninja_overlay" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- INinja Implementations ----------------
|
||||
|
||||
/** The parameter for the ninja immobile state. */
|
||||
private static final DataParameter<Boolean> IS_HIDING = EntityDataManager.defineId( NinjaWitherSkeletonEntity.class, DataSerializers.BOOLEAN );
|
||||
/** The parameter for the ninja disguise block. */
|
||||
private static final DataParameter<Optional<BlockState>> HIDING_BLOCK = EntityDataManager.defineId( NinjaWitherSkeletonEntity.class, DataSerializers.BLOCK_STATE );
|
||||
|
||||
private boolean canHide = true;
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
entityData.define( IS_HIDING, false );
|
||||
entityData.define( HIDING_BLOCK, Optional.empty() );
|
||||
}
|
||||
|
||||
/** @return Whether this ninja is currently immobile. */
|
||||
@Override
|
||||
public boolean isImmobile() { return getEntityData().get( IS_HIDING ); }
|
||||
|
||||
/** Sets this ninja's immovable state. When activated, the entity is 'snapped' to the nearest block position. */
|
||||
@Override
|
||||
public void setImmobile( boolean value ) {
|
||||
if( value != isImmobile() ) {
|
||||
getEntityData().set( IS_HIDING, value );
|
||||
if( value ) {
|
||||
clearFire();
|
||||
moveTo( Math.floor( getX() ) + 0.5, Math.floor( getY() ), Math.floor( getZ() ) + 0.5 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The block being hidden (rendered) as, or null if not hiding. */
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getDisguiseBlock() {
|
||||
if( isAlive() ) return getEntityData().get( HIDING_BLOCK ).orElse( null );
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Sets the block being hidden (rendered) as, set to null to cancel hiding. */
|
||||
@Override
|
||||
public void setDisguiseBlock( @Nullable BlockState block ) {
|
||||
getEntityData().set( HIDING_BLOCK, Optional.ofNullable( block ) );
|
||||
canHide = false;
|
||||
|
||||
// Smoke puff when emerging from disguise
|
||||
if( block == null ) {
|
||||
//spawnExplosionParticle(); TODO
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ public class SpitfireWitherSkeletonEntity extends _SpecialWitherSkeletonEntity {
|
|||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.95F, 3.24F );
|
||||
entityType.sized( 0.95F, 3.6F );
|
||||
return new BestiaryInfo( 0xDC1A00, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public class _SpecialWitherSkeletonEntity extends WitherSkeletonEntity implement
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialWitherSkeletonEntity( EntityType<? extends _SpecialWitherSkeletonEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
getSpecialData().initialize();
|
||||
getSpecialData().setImmuneToFire( true );
|
||||
}
|
||||
|
||||
|
@ -162,14 +162,11 @@ public class _SpecialWitherSkeletonEntity extends WitherSkeletonEntity implement
|
|||
return arrow;
|
||||
}
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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. */
|
||||
|
@ -207,7 +204,7 @@ public class _SpecialWitherSkeletonEntity extends WitherSkeletonEntity implement
|
|||
return groupData;
|
||||
}
|
||||
|
||||
/** Called to change */
|
||||
/** Called to set this entity's attack AI based on current equipment. */
|
||||
@Override
|
||||
public void reassessWeaponGoal() {
|
||||
if( level != null && !level.isClientSide ) {
|
||||
|
@ -315,13 +312,13 @@ public class _SpecialWitherSkeletonEntity extends WitherSkeletonEntity implement
|
|||
|
||||
/** @return The eye height of this entity when standing. */
|
||||
@Override
|
||||
protected float getStandingEyeHeight( Pose pose, EntitySize size ) {//TODO fix this
|
||||
return super.getStandingEyeHeight( pose, size ) * getSpecialData().getBaseScale() * (isBaby() ? 0.53448F : 1.0F);
|
||||
protected float getStandingEyeHeight( Pose pose, EntitySize size ) {
|
||||
return 1.74F * getSpecialData().getBaseScale() * (isBaby() ? 0.53448F : 1.0F); // Use base skeleton scale instead of super
|
||||
}
|
||||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -336,7 +333,7 @@ public class _SpecialWitherSkeletonEntity extends WitherSkeletonEntity implement
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.entity.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.entity.projectile.ArrowEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class BruteZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.7F, 2.35F );
|
||||
return new BestiaryInfo( 0xFFF87E );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialZombieEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.addAttribute( Attributes.ARMOR, 10.0 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Zombie Brute",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.FLINT, 1 );
|
||||
loot.addRareDrop( "rare", Items.IRON_INGOT );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public BruteZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( target instanceof LivingEntity ) {
|
||||
MobHelper.causeLifeLoss( (LivingEntity) target, 2.0F );
|
||||
}
|
||||
}
|
||||
|
||||
/** Override to modify this entity's ranged attack projectile. */
|
||||
@Override
|
||||
protected AbstractArrowEntity getVariantArrow( AbstractArrowEntity arrow, ItemStack arrowItem, float damageMulti ) {
|
||||
if( arrow instanceof ArrowEntity ) {
|
||||
((ArrowEntity) arrow).addEffect( new EffectInstance( Effects.HARM, 1 ) );
|
||||
}
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "brute" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "brute_overlay" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
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.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class FireZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0xDC1A00 );
|
||||
//TODO theme - fire
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialZombieEntity.createAttributes();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Fire Zombie",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.FIRE_CHARGE );
|
||||
loot.addUncommonDrop( "uncommon", Items.COAL );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public FireZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToFire( true );
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
target.setSecondsOnFire( 10 );
|
||||
}
|
||||
|
||||
/** Override to modify this entity's ranged attack projectile. */
|
||||
@Override
|
||||
protected AbstractArrowEntity getVariantArrow( AbstractArrowEntity arrow, ItemStack arrowItem, float damageMulti ) {
|
||||
arrow.setSecondsOnFire( 100 );
|
||||
return arrow;
|
||||
}
|
||||
|
||||
/** @return The sound this entity makes idly. */
|
||||
@Override
|
||||
protected SoundEvent getAmbientSound() { return SoundEvents.HUSK_AMBIENT; }
|
||||
|
||||
/** @return The sound this entity makes when damaged. */
|
||||
@Override
|
||||
protected SoundEvent getHurtSound( DamageSource source ) { return SoundEvents.HUSK_HURT; }
|
||||
|
||||
/** @return The sound this entity makes when killed. */
|
||||
@Override
|
||||
protected SoundEvent getDeathSound() { return SoundEvents.HUSK_DEATH; }
|
||||
|
||||
/** @return The sound this entity makes while walking. */
|
||||
@Override
|
||||
protected SoundEvent getStepSound() { return SoundEvents.HUSK_STEP; }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "fire" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.IAngler;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootEntryItemBuilder;
|
||||
import fathertoast.specialmobs.datagen.loot.LootHelper;
|
||||
import fathertoast.specialmobs.datagen.loot.LootPoolBuilder;
|
||||
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.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.FishingRodItem;
|
||||
import net.minecraft.item.IDyeableArmorItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class FishingZombieEntity extends _SpecialZombieEntity implements IAngler {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x2D41F4 );
|
||||
//TODO theme - fishing
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialZombieEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.8 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Fishing Zombie",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addPool( new LootPoolBuilder( "common" )
|
||||
.addEntry( new LootEntryItemBuilder( Items.COD ).setCount( 0, 2 ).addLootingBonus( 0, 1 ).smeltIfBurning().toLootEntry() )
|
||||
.toLootPool() );
|
||||
loot.addPool( new LootPoolBuilder( "rare" ).addConditions( LootHelper.RARE_CONDITIONS )
|
||||
.addEntry( new LootEntryItemBuilder( Items.FISHING_ROD ).enchant( 30, true ).toLootEntry() )
|
||||
.toLootPool() );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public FishingZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setCanBreatheInWater( true );
|
||||
getSpecialData().setIgnoreWaterPush( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackSpread = 10.0F;
|
||||
getSpecialData().rangedAttackCooldown = 32;
|
||||
getSpecialData().rangedAttackMaxCooldown = 48;
|
||||
getSpecialData().rangedAttackMaxRange = 10.0F;
|
||||
|
||||
//TODO add angler AI @ attack priority
|
||||
}
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
|
||||
setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( Items.FISHING_ROD ) );
|
||||
if( getItemBySlot( EquipmentSlotType.FEET ).isEmpty() ) {
|
||||
ItemStack booties = new ItemStack( Items.LEATHER_BOOTS );
|
||||
((IDyeableArmorItem) booties.getItem()).setColor( booties, 0xFFFF00 );
|
||||
setItemSlot( EquipmentSlotType.FEET, booties );
|
||||
}
|
||||
setCanPickUpLoot( false );
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a bow. */
|
||||
@Override
|
||||
protected double getVariantBowChance() { return 0.0; }
|
||||
|
||||
|
||||
//--------------- IAngler Implementations ----------------
|
||||
|
||||
/** The parameter for baby status. */
|
||||
private static final DataParameter<Boolean> IS_LINE_OUT = EntityDataManager.defineId( FishingZombieEntity.class, DataSerializers.BOOLEAN );
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
entityData.define( IS_LINE_OUT, false );
|
||||
}
|
||||
|
||||
/** Sets this angler's line as out (or in). */
|
||||
@Override
|
||||
public void setLineOut( boolean value ) { getEntityData().set( IS_LINE_OUT, value ); }
|
||||
|
||||
/** @return Whether this angler's line is out. */
|
||||
@Override
|
||||
public boolean isLineOut() { return getEntityData().get( IS_LINE_OUT ); }
|
||||
|
||||
/** @return The item equipped in a particular slot. */
|
||||
@Override
|
||||
public ItemStack getItemBySlot( EquipmentSlotType slot ) {
|
||||
// Display a stick in place of the "cast fishing rod" when the fancy render is disabled
|
||||
if( level.isClientSide() && /*!Config.get().GENERAL.FANCY_FISHING_MOBS &&*/ EquipmentSlotType.MAINHAND.equals( slot ) ) {
|
||||
final ItemStack held = super.getItemBySlot( slot );
|
||||
if( !held.isEmpty() && held.getItem() instanceof FishingRodItem && isLineOut() ) {
|
||||
return new ItemStack( Items.STICK );
|
||||
}
|
||||
return held;
|
||||
}
|
||||
return super.getItemBySlot( slot );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.item.Items;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class GiantZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.95F );
|
||||
return new BestiaryInfo( 0x799C65 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialZombieEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Giant Zombie",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addGuaranteedDrop( "base", Items.ROTTEN_FLESH, 2 );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public GiantZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
maxUpStep = 1.0F;
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 2.0F;
|
||||
}
|
||||
|
||||
/** Sets this entity as a baby. */
|
||||
@Override
|
||||
public void setBaby( boolean value ) { }
|
||||
|
||||
/** @return True if this entity is a baby. */
|
||||
@Override
|
||||
public boolean isBaby() { return false; }
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Food;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class HungryZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xAB1518 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialZombieEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Hungry Zombie",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addCommonDrop( "common", Items.BONE );
|
||||
loot.addUncommonDrop( "uncommon", Items.BEEF, Items.CHICKEN, Items.MUTTON, Items.PORKCHOP, Items.RABBIT, Items.COOKIE );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public HungryZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setRegenerationTime( 30 );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
disableRangedAI();
|
||||
}
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
setCanPickUpLoot( false );
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a bow. */
|
||||
@Override
|
||||
protected double getVariantBowChance() { return 0.0; }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( level.isClientSide() ) return;
|
||||
|
||||
if( target instanceof PlayerEntity && ForgeEventFactory.getMobGriefingEvent( level, this ) ) {
|
||||
final ItemStack food = MobHelper.stealRandomFood( (PlayerEntity) target );
|
||||
if( !food.isEmpty() ) {
|
||||
final Food foodStats = food.getItem().getFoodProperties();
|
||||
heal( Math.max( foodStats == null ? 0.0F : foodStats.getNutrition(), 1.0F ) );
|
||||
playSound( SoundEvents.PLAYER_BURP, 0.5F, random.nextFloat() * 0.1F + 0.9F );
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Take a bite out of the target if they have no food to eat
|
||||
if( target instanceof LivingEntity ) {
|
||||
MobHelper.stealLife( this, (LivingEntity) target, 2.0F );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "hungry" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.AttributeModifierMap;
|
||||
import net.minecraft.entity.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.entity.projectile.ArrowEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class HuskZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xE6CC94, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - desert
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return _SpecialZombieEntity.createAttributes();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Husk",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
loot.addLootTable( "main", EntityType.HUSK.getDefaultLootTable() );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public HuskZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.0625F );
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( target instanceof LivingEntity ) {
|
||||
final LivingEntity livingTarget = (LivingEntity) target;
|
||||
final int duration = MobHelper.getDebuffDuration( level.getDifficulty() );
|
||||
|
||||
livingTarget.addEffect( new EffectInstance( Effects.HUNGER, duration ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** Override to modify this entity's ranged attack projectile. */
|
||||
@Override
|
||||
protected AbstractArrowEntity getVariantArrow( AbstractArrowEntity arrow, ItemStack arrowItem, float damageMulti ) {
|
||||
if( arrow instanceof ArrowEntity ) {
|
||||
final int duration = MobHelper.getDebuffDuration( level.getDifficulty() );
|
||||
|
||||
((ArrowEntity) arrow).addEffect( new EffectInstance( Effects.HUNGER, duration ) );
|
||||
}
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/zombie/husk.png" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- Husk Implementations ----------------
|
||||
|
||||
/** @return True if this zombie burns in sunlight. */
|
||||
@Override
|
||||
protected boolean isSunSensitive() { return false; }
|
||||
|
||||
/** @return The sound this entity makes idly. */
|
||||
@Override
|
||||
protected SoundEvent getAmbientSound() { return SoundEvents.HUSK_AMBIENT; }
|
||||
|
||||
/** @return The sound this entity makes when damaged. */
|
||||
@Override
|
||||
protected SoundEvent getHurtSound( DamageSource source ) { return SoundEvents.HUSK_HURT; }
|
||||
|
||||
/** @return The sound this entity makes when killed. */
|
||||
@Override
|
||||
protected SoundEvent getDeathSound() { return SoundEvents.HUSK_DEATH; }
|
||||
|
||||
/** @return The sound this entity makes while walking. */
|
||||
@Override
|
||||
protected SoundEvent getStepSound() { return SoundEvents.HUSK_STEP; }
|
||||
}
|
|
@ -10,20 +10,19 @@ 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.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.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
|
@ -70,11 +69,30 @@ public class MadScientistZombieEntity extends _SpecialZombieEntity {
|
|||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
disableRangedAI();
|
||||
|
||||
AIHelper.insertGoal( goalSelector, 2, new SpecialInjectCreeperGoal<>(
|
||||
this, 1.0D, 20.0D,
|
||||
( madman, creeper ) -> creeper.isAlive() && !creeper.isPowered() && madman.getSensing().canSee( creeper ) ) );
|
||||
}
|
||||
|
||||
/** Override to change this entity's attack goal priority. */
|
||||
@Override
|
||||
protected int getVariantAttackPriority() { return super.getVariantAttackPriority() + 1; }
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
|
||||
setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( SMItems.SYRINGE.get() ) );
|
||||
setDropChance( EquipmentSlotType.MAINHAND, 0.0F );
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a bow. */
|
||||
@Override
|
||||
protected double getVariantBowChance() { return 0.0; }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
|
@ -86,27 +104,6 @@ public class MadScientistZombieEntity extends _SpecialZombieEntity {
|
|||
}
|
||||
}
|
||||
|
||||
/** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
|
||||
@Nullable
|
||||
@Override
|
||||
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
|
||||
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
|
||||
this.populateDefaultEquipmentSlots( difficulty );
|
||||
return super.finalizeSpawn( world, difficulty, spawnReason, groupData, eggTag );
|
||||
}
|
||||
|
||||
/** Only drop armor. The syringe item should be dropped from the loot table, and not from the hand item. **/
|
||||
@Override
|
||||
protected float getEquipmentDropChance( EquipmentSlotType slotType ) {
|
||||
return slotType.getType() == EquipmentSlotType.Group.ARMOR ? this.armorDropChances[slotType.getIndex()] : 0.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficultyInstance ) {
|
||||
super.populateDefaultEquipmentSlots( difficultyInstance );
|
||||
this.setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( SMItems.SYRINGE.get() ) );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "madscientist" ),
|
||||
null,
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package fathertoast.specialmobs.common.entity.zombie;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
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.block.Blocks;
|
||||
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.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.entity.projectile.ArrowEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class PlagueZombieEntity extends _SpecialZombieEntity {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x8AA838 );
|
||||
//TODO theme - forest
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialZombieEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.1 )
|
||||
.build();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Plague Zombie",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
loot.addUncommonDrop( "uncommon", Items.POISONOUS_POTATO, Items.SPIDER_EYE, Items.FERMENTED_SPIDER_EYE,
|
||||
Blocks.RED_MUSHROOM, Blocks.BROWN_MUSHROOM );
|
||||
}
|
||||
|
||||
@SpecialMob.Constructor
|
||||
public PlagueZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
if( target instanceof LivingEntity ) {
|
||||
((LivingEntity) target).addEffect( MobHelper.nextPlagueEffect( random, level ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** Override to modify this entity's ranged attack projectile. */
|
||||
@Override
|
||||
protected AbstractArrowEntity getVariantArrow( AbstractArrowEntity arrow, ItemStack arrowItem, float damageMulti ) {
|
||||
if( arrow instanceof ArrowEntity ) {
|
||||
((ArrowEntity) arrow).addEffect( MobHelper.nextPlagueEffect( random, level ) );
|
||||
}
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "plague" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -6,15 +6,25 @@ import fathertoast.specialmobs.common.core.SpecialMobs;
|
|||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
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.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.goal.RangedBowAttackGoal;
|
||||
import net.minecraft.entity.ai.goal.ZombieAttackGoal;
|
||||
import net.minecraft.entity.monster.ZombieEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.entity.projectile.ProjectileHelper;
|
||||
import net.minecraft.entity.projectile.SnowballEntity;
|
||||
import net.minecraft.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.BowItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
|
@ -22,6 +32,8 @@ 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.SoundEvents;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
|
@ -33,13 +45,13 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
|||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_SpecialZombieEntity> {
|
||||
public class _SpecialZombieEntity extends ZombieEntity implements IRangedAttackMob, ISpecialMob<_SpecialZombieEntity> {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x799C65 );
|
||||
return new BestiaryInfo( 0x799C65 );//sized(0.6F, 1.95F)
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
|
@ -61,7 +73,8 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
@SpecialMob.Constructor
|
||||
public _SpecialZombieEntity( EntityType<? extends _SpecialZombieEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
specialData.initialize();
|
||||
reassessWeaponGoal();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,9 +84,11 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
@Override
|
||||
protected void registerGoals() {
|
||||
super.registerGoals();
|
||||
AIHelper.removeGoals( goalSelector, ZombieAttackGoal.class );
|
||||
|
||||
getSpecialData().rangedAttackDamage = 2.0F;
|
||||
getSpecialData().rangedAttackSpread = 18.0F;
|
||||
getSpecialData().rangedAttackSpread = 20.0F;
|
||||
getSpecialData().rangedWalkSpeed = 0.8F;
|
||||
getSpecialData().rangedAttackCooldown = 30;
|
||||
getSpecialData().rangedAttackMaxCooldown = getSpecialData().rangedAttackCooldown;
|
||||
getSpecialData().rangedAttackMaxRange = 12.0F;
|
||||
|
@ -83,14 +98,73 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Called to melee attack the target. */
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void disableRangedAI() { setRangedAI( 1.0, 20, 0.0F ); }
|
||||
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void setRangedAI( double walkSpeed, int cooldownTime ) {
|
||||
getSpecialData().rangedWalkSpeed = (float) walkSpeed;
|
||||
getSpecialData().rangedAttackCooldown = cooldownTime;
|
||||
getSpecialData().rangedAttackMaxCooldown = cooldownTime;
|
||||
}
|
||||
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void setRangedAI( double walkSpeed, int cooldownTime, float range ) {
|
||||
setRangedAI( walkSpeed, cooldownTime );
|
||||
getSpecialData().rangedAttackMaxRange = range;
|
||||
}
|
||||
|
||||
/** Override to change this entity's attack goal priority. */
|
||||
protected int getVariantAttackPriority() { return 2; }
|
||||
|
||||
/** Called during spawn finalization to set starting equipment. */
|
||||
@Override
|
||||
public boolean doHurtTarget( Entity target ) {
|
||||
if( super.doHurtTarget( target ) ) {
|
||||
onVariantAttack( target );
|
||||
return true;
|
||||
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
|
||||
super.populateDefaultEquipmentSlots( difficulty );
|
||||
if( random.nextDouble() < getVariantBowChance() ) { //TODO config the default 5% chance
|
||||
setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( Items.BOW ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Override to change this entity's chance to spawn with a bow. */
|
||||
protected double getVariantBowChance() { return getSpecialData().rangedAttackMaxRange > 0.0F ? 0.05 : 0.0; }
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
@Override
|
||||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
final ItemStack arrowItem = getProjectile( getItemInHand( ProjectileHelper.getWeaponHoldingHand(
|
||||
this, item -> item instanceof BowItem ) ) );
|
||||
AbstractArrowEntity arrow = getArrow( arrowItem, damageMulti );
|
||||
if( getMainHandItem().getItem() instanceof BowItem )
|
||||
arrow = ((BowItem) getMainHandItem().getItem()).customArrow( arrow );
|
||||
|
||||
final double dX = target.getX() - getX();
|
||||
final double dY = target.getY( 1.0 / 3.0 ) - arrow.getY();
|
||||
final double dZ = target.getZ() - getZ();
|
||||
final double dH = MathHelper.sqrt( dX * dX + dZ * dZ );
|
||||
arrow.shoot( dX, dY + dH * 0.2, dZ, 1.6F,
|
||||
getSpecialData().rangedAttackSpread * (1.0F - 0.2858F * level.getDifficulty().getId()) );
|
||||
|
||||
playSound( SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (random.nextFloat() * 0.4F + 0.8F) );
|
||||
level.addFreshEntity( arrow );
|
||||
}
|
||||
|
||||
/** @return The arrow for this zombie to shoot. */
|
||||
protected AbstractArrowEntity getArrow( ItemStack arrowItem, float damageMulti ) {
|
||||
return getVariantArrow( ProjectileHelper.getMobArrow( this, arrowItem,
|
||||
damageMulti * getSpecialData().rangedAttackDamage ), arrowItem, damageMulti );
|
||||
}
|
||||
|
||||
/** Override to modify this entity's ranged attack projectile. */
|
||||
protected AbstractArrowEntity getVariantArrow( AbstractArrowEntity arrow, ItemStack arrowItem, float damageMulti ) {
|
||||
return arrow;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
|
@ -108,6 +182,9 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
/** The parameter for special mob render scale. */
|
||||
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialZombieEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
/** This entity's attack AI. */
|
||||
private Goal currentAttackAI;
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
|
@ -120,10 +197,36 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
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
|
||||
reassessWeaponGoal();
|
||||
return groupData;
|
||||
}
|
||||
|
||||
/** Called to set the item equipped in a particular slot. */
|
||||
@Override
|
||||
public void setItemSlot( EquipmentSlotType slot, ItemStack item ) {
|
||||
super.setItemSlot( slot, item );
|
||||
if( !level.isClientSide ) reassessWeaponGoal();
|
||||
}
|
||||
|
||||
/** Called to set this entity's attack AI based on current equipment. */
|
||||
public void reassessWeaponGoal() {
|
||||
if( level != null && !level.isClientSide ) {
|
||||
if( currentAttackAI != null ) goalSelector.removeGoal( currentAttackAI );
|
||||
|
||||
final SpecialMobData<_SpecialZombieEntity> data = getSpecialData();
|
||||
final ItemStack weapon = getItemInHand( ProjectileHelper.getWeaponHoldingHand(
|
||||
this, item -> item instanceof BowItem ) );
|
||||
if( data.rangedAttackMaxRange > 0.0F && weapon.getItem() == Items.BOW ) {
|
||||
currentAttackAI = new RangedBowAttackGoal<>( this, data.rangedWalkSpeed,
|
||||
data.rangedAttackCooldown, data.rangedAttackMaxRange );
|
||||
}
|
||||
else {
|
||||
currentAttackAI = new ZombieAttackGoal( this, 1.0, false );
|
||||
}
|
||||
goalSelector.addGoal( getVariantAttackPriority(), currentAttackAI );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------- ISpecialMob Implementation ----------------
|
||||
|
||||
|
@ -164,12 +267,12 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
/** @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 super.getStandingEyeHeight( pose, size ) * getSpecialData().getBaseScale();// * (isBaby() ? 0.53448F : 1.0F); - Handled in super
|
||||
}
|
||||
|
||||
/** @return Whether this entity is immune to fire damage. */
|
||||
@Override
|
||||
public boolean fireImmune() { return specialData.isImmuneToFire(); }
|
||||
public boolean fireImmune() { return getSpecialData().isImmuneToFire(); }
|
||||
|
||||
/** Sets this entity on fire for a specific duration. */
|
||||
@Override
|
||||
|
@ -177,6 +280,10 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
if( !getSpecialData().isImmuneToBurning() ) super.setRemainingFireTicks( ticks );
|
||||
}
|
||||
|
||||
/** @return True if this zombie burns in sunlight. */
|
||||
@Override
|
||||
protected boolean isSunSensitive() { return !getSpecialData().isImmuneToFire() && !getSpecialData().isImmuneToBurning(); }
|
||||
|
||||
/** @return True if this entity can be leashed. */
|
||||
@Override
|
||||
public boolean canBeLeashed( PlayerEntity player ) { return !isLeashed() && getSpecialData().allowLeashing(); }
|
||||
|
@ -184,7 +291,7 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
/** 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( specialData.canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
if( getSpecialData().canBeStuckIn( block ) ) super.makeStuckInBlock( block, speedMulti );
|
||||
}
|
||||
|
||||
/** @return Called when this mob falls. Calculates and applies fall damage. Returns false if canceled. */
|
||||
|
@ -246,5 +353,7 @@ public class _SpecialZombieEntity extends ZombieEntity implements ISpecialMob<_S
|
|||
|
||||
getSpecialData().readFromNBT( saveTag );
|
||||
readVariantSaveData( saveTag );
|
||||
|
||||
reassessWeaponGoal();
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ public final class References {
|
|||
public static final String TAG_HEALTH_STACKS = "HealthStacks"; // Hungry Spider
|
||||
|
||||
// Misc.
|
||||
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_IS_FAKE = "IsFake"; // Mirage Enderman
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue