TSO, SPIDER, XM8

This commit is contained in:
FatherToast 2022-06-23 20:31:46 -05:00
parent 932aca1ad8
commit 00f6912c6d
23 changed files with 1547 additions and 75 deletions

View file

@ -2,6 +2,7 @@ package fathertoast.specialmobs.client;
import fathertoast.specialmobs.client.renderer.entity.SpecialCreeperRenderer; import fathertoast.specialmobs.client.renderer.entity.SpecialCreeperRenderer;
import fathertoast.specialmobs.client.renderer.entity.SpecialSkeletonRenderer; import fathertoast.specialmobs.client.renderer.entity.SpecialSkeletonRenderer;
import fathertoast.specialmobs.client.renderer.entity.SpecialSpiderRenderer;
import fathertoast.specialmobs.common.bestiary.MobFamily; import fathertoast.specialmobs.common.bestiary.MobFamily;
import fathertoast.specialmobs.common.core.SpecialMobs; import fathertoast.specialmobs.common.core.SpecialMobs;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
@ -29,6 +30,8 @@ public class ClientRegister {
// Family-based renderers // Family-based renderers
registerFamilyRenderers( MobFamily.CREEPER, SpecialCreeperRenderer::new ); registerFamilyRenderers( MobFamily.CREEPER, SpecialCreeperRenderer::new );
//registerFamilyRenderers( MobFamily.SKELETON, SpecialSkeletonRenderer::new ); //registerFamilyRenderers( MobFamily.SKELETON, SpecialSkeletonRenderer::new );
registerFamilyRenderers( MobFamily.SPIDER, SpecialSpiderRenderer::new );
//registerFamilyRenderers( MobFamily.CAVE_SPIDER, SpecialSpiderRenderer::new );
} }
private static <T extends LivingEntity> void registerFamilyRenderers( MobFamily<T> family, IRenderFactory<? super T> renderFactory ) { private static <T extends LivingEntity> void registerFamilyRenderers( MobFamily<T> family, IRenderFactory<? super T> renderFactory ) {

View file

@ -0,0 +1,50 @@
package fathertoast.specialmobs.client.renderer.entity;
import com.mojang.blaze3d.matrix.MatrixStack;
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
import fathertoast.specialmobs.common.entity.ISpecialMob;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.entity.CreeperRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.SpiderRenderer;
import net.minecraft.client.renderer.entity.model.CreeperModel;
import net.minecraft.client.renderer.entity.model.SpiderModel;
import net.minecraft.entity.monster.CreeperEntity;
import net.minecraft.entity.monster.SpiderEntity;
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 SpecialSpiderRenderer extends SpiderRenderer<SpiderEntity> {
private final float baseShadowRadius;
public SpecialSpiderRenderer( EntityRendererManager rendererManager ) {
super( rendererManager );
layers.remove( layers.size() - 1 ); // Remove vanilla eyes layer
baseShadowRadius = shadowRadius;
addLayer( new SpecialMobEyesLayer<>( this ) );
// Model doesn't support size parameter
//addLayer( new SpecialMobOverlayLayer<>( this, new SpiderModel<>( 0.25F ) ) );
}
@Override
public ResourceLocation getTextureLocation( SpiderEntity entity ) {
return ((ISpecialMob<?>) entity).getSpecialData().getTexture();
}
@Override
protected void scale( SpiderEntity entity, MatrixStack matrixStack, float partialTick ) {
super.scale( entity, matrixStack, partialTick );
final float scale = ((ISpecialMob<?>) entity).getSpecialData().getRenderScale();
shadowRadius = baseShadowRadius * scale;
matrixStack.scale( scale, scale, scale );
}
}

View file

@ -1,22 +1,14 @@
package fathertoast.specialmobs.common.bestiary; package fathertoast.specialmobs.common.bestiary;
//import net.minecraft.init.Biomes;
import net.minecraft.world.DimensionType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class BestiaryInfo { public class BestiaryInfo {
public enum BaseWeight { public enum BaseWeight {
DEFAULT( 600 ), DEFAULT( 600 ),
HIGHEST( DEFAULT.value * 8 ), DISABLED( 0 ),
HIGH( DEFAULT.value * 4 ), LOWEST( DEFAULT.value / 8 ),
LOW( DEFAULT.value / 4 ), LOW( DEFAULT.value / 4 ),
LOWEST( DEFAULT.value / 8 ); HIGH( DEFAULT.value * 4 ),
HIGHEST( DEFAULT.value * 8 );
public final int value; public final int value;
@ -24,6 +16,7 @@ public class BestiaryInfo {
} }
//TODO default themes //TODO default themes
// public static final EnvironmentListConfig DEFAULT_THEME_FIRE = new EnvironmentListConfig( // public static final EnvironmentListConfig DEFAULT_THEME_FIRE = new EnvironmentListConfig(
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_COMMON ), // new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_COMMON ),
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_COMMON ), // new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_COMMON ),

View file

@ -10,6 +10,7 @@ import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.monster.AbstractSkeletonEntity; import net.minecraft.entity.monster.AbstractSkeletonEntity;
import net.minecraft.entity.monster.CreeperEntity; import net.minecraft.entity.monster.CreeperEntity;
import net.minecraft.entity.monster.SpiderEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.ForgeSpawnEggItem; import net.minecraftforge.common.ForgeSpawnEggItem;
@ -71,10 +72,10 @@ public class MobFamily<T extends LivingEntity> {
// "Flying", "Hardened", "Sticky", "Volatile" // "Flying", "Hardened", "Sticky", "Volatile"
// ); // );
// public static final MobFamily<SpiderEntity> SPIDER = new MobFamily<>( public static final MobFamily<SpiderEntity> SPIDER = new MobFamily<>(
// "Spider", "spiders", 0x342D27, new EntityType[] { EntityType.SPIDER }, "Spider", "spiders", 0x342D27, new EntityType[] { EntityType.SPIDER },
// "Baby", "Desert", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", "Web", "Witch" "Baby", "Desert", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", "Web", "Witch"
// ); );
// public static final MobFamily<CaveSpiderEntity> CAVE_SPIDER = new MobFamily<>( // public static final MobFamily<CaveSpiderEntity> CAVE_SPIDER = new MobFamily<>(
// "CaveSpider", "cave spiders", 0x0C424E, new EntityType[] { EntityType.CAVE_SPIDER }, // "CaveSpider", "cave spiders", 0x0C424E, new EntityType[] { EntityType.CAVE_SPIDER },
// "Baby", "Flying", "Mother", "Web", "Witch" // "Baby", "Flying", "Mother", "Web", "Witch"

View file

@ -0,0 +1,184 @@
package fathertoast.specialmobs.common.entity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.CreatureAttribute;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.EffectType;
import net.minecraft.potion.Effects;
import net.minecraft.util.DamageSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.Random;
public final class MobHelper {
/** Pool of effects to choose from for plague-type mobs to apply on hit. Duration is a multiplier. */
private static final EffectInstance[] PLAGUE_EFFECTS = {
new EffectInstance( Effects.MOVEMENT_SLOWDOWN, 2, 0 ),
new EffectInstance( Effects.DIG_SLOWDOWN, 2, 1 ),
new EffectInstance( Effects.BLINDNESS, 1, 0 ),
new EffectInstance( Effects.HUNGER, 2, 0 ),
new EffectInstance( Effects.WEAKNESS, 1, 0 ),
new EffectInstance( Effects.POISON, 1, 0 ),
new EffectInstance( Effects.CONFUSION, 2, 0 ) // Keep this option last for easy disable (by config)
};
/** Pool of effects to choose from for witch-spider-type mobs to apply on hit. Duration is a multiplier. */
private static final EffectInstance[] WITCH_EFFECTS = {
new EffectInstance( Effects.MOVEMENT_SLOWDOWN, 1, 1 ),
new EffectInstance( Effects.DIG_SLOWDOWN, 2, 1 ),
new EffectInstance( Effects.DAMAGE_RESISTANCE, 1, -3 ),
new EffectInstance( Effects.BLINDNESS, 1, 0 ),
new EffectInstance( Effects.HUNGER, 2, 0 ),
new EffectInstance( Effects.WEAKNESS, 1, 0 ),
new EffectInstance( Effects.WITHER, 1, 0 ),
new EffectInstance( Effects.LEVITATION, 1, 1 ),
new EffectInstance( Effects.POISON, 1, 0 ) // Keep this option last for easy disable (by cave spiders)
};
/** @return True if the damage source can deal normal damage to vampire-type mobs (e.g., wooden or smiting weapons). */
public static boolean isDamageSourceIneffectiveAgainstVampires( DamageSource source ) {
if( source != null ) {
if( source.isBypassMagic() || source.isBypassInvul() ) return false;
final Entity attacker = source.getEntity();
if( attacker instanceof LivingEntity ) {
final ItemStack weapon = ((LivingEntity) attacker).getMainHandItem();
return !isWoodenTool( weapon ) && !hasSmite( weapon );
}
}
return true;
}
/** @return True if the given item is made of wood. */
private static boolean isWoodenTool( ItemStack item ) {
//TODO Consider Tinkers compat - striking component must be wood
return !item.isEmpty() && item.getItem() instanceof TieredItem && ((TieredItem) item.getItem()).getTier() == ItemTier.WOOD;
}
/** @return True if the given item deals bonus damage against undead. */
private static boolean hasSmite( ItemStack item ) {
//TODO Consider Tinkers compat if this doesn't already work - must have smite modifier
return EnchantmentHelper.getDamageBonus( item, CreatureAttribute.UNDEAD ) > 0.0F;
}
/**
* Reduces the target's life directly. Will not reduce health below 1.
*
* @param target The entity to cause life loss on.
* @param amount The amount of life loss to inflict.
*/
public static void causeLifeLoss( LivingEntity target, float amount ) {
final float currentHealth = target.getHealth();
if( currentHealth > 1.0F ) {
target.setHealth( Math.max( 1.0F, currentHealth - amount ) );
}
}
/**
* Reduces the target's life directly and heals the attacker by the amount lost.
* Will not reduce health below 1.
*
* @param attacker The entity causing the life steal.
* @param target The entity to steal life from.
* @param amount The amount of life steal to inflict.
*/
public static void stealLife( LivingEntity attacker, LivingEntity target, float amount ) {
final float currentHealth = target.getHealth();
if( currentHealth > 1.0F ) {
final float newHealth = Math.max( 1.0F, currentHealth - amount );
target.setHealth( newHealth );
attacker.heal( currentHealth - newHealth );
}
}
/**
* Removes one random food item from the player's inventory and returns it.
* Returns an empty stack if there is no food in the player's inventory.
*
* @param player The player to steal from.
* @return The item removed from the player's inventory.
*/
public static ItemStack stealRandomFood( PlayerEntity player ) {
final ArrayList<Integer> foodSlots = new ArrayList<>();
for( int slot = 0; slot < player.inventory.getContainerSize(); slot++ ) {
final ItemStack item = player.inventory.getItem( slot );
if( !item.isEmpty() && item.getItem().getFoodProperties() != null ) foodSlots.add( slot );
}
if( !foodSlots.isEmpty() ) {
return player.inventory.removeItem( foodSlots.get( player.getRandom().nextInt( foodSlots.size() ) ), 1 );
}
return ItemStack.EMPTY;
}
/**
* Steals a non-harmful potion effect from a target and applies it to the attacker with a minimum duration of 5 seconds.
*
* @param attacker The entity stealing an effect.
* @param target The entity to steal an effect from.
*/
public static void stealBuffEffect( LivingEntity attacker, LivingEntity target ) {
if( !attacker.level.isClientSide() ) {
for( EffectInstance potion : target.getActiveEffects() ) {
if( potion != null && potion.getEffect().getCategory() != EffectType.HARMFUL && potion.getAmplifier() >= 0 ) {
target.removeEffect( potion.getEffect() );
attacker.addEffect( new EffectInstance( potion.getEffect(),
Math.max( potion.getDuration(), 200 ), potion.getAmplifier() ) );
return;
}
}
}
}
/** @return The base debuff duration. */
public static int getDebuffDuration( Difficulty difficulty ) {
switch( difficulty ) {
case PEACEFUL:
case EASY:
return 60;
case NORMAL:
return 140;
default:
return 300;
}
}
/**
* Makes a random potion effect for a plague-type mob to apply on hit.
*
* @param random The rng to draw from.
* @param world The context.
* @return A newly created potion effect instance we can apply to an entity.
*/
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 )];
return new EffectInstance( potion.getEffect(), duration * potion.getDuration(), potion.getAmplifier() );
}
/**
* Makes a random potion effect for a witch-spider-type mob to apply on hit,
* optionally including poison in the effect pool.
* <p>
* For example, witch cave spiders do not include poison in the pool because they apply poison already.
*
* @param random The rng to draw from.
* @param world The context.
* @param includePoison Whether to include poison in the potion pool.
* @return A newly created potion effect instance we can apply to an entity.
*/
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) )];
return new EffectInstance( potion.getEffect(), duration * potion.getDuration(), potion.getAmplifier() );
}
}

View file

@ -23,6 +23,7 @@ import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.Explosion; import net.minecraft.world.Explosion;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.spawner.WorldEntitySpawner; import net.minecraft.world.spawner.WorldEntitySpawner;
@ -146,6 +147,7 @@ public class DrowningCreeperEntity extends _SpecialCreeperEntity {
/** Helper method to simplify spawning pufferfish. */ /** Helper method to simplify spawning pufferfish. */
private void spawnPufferfish( BlockPos pos ) { private void spawnPufferfish( BlockPos pos ) {
if( !(level instanceof IServerWorld) ) return;
final PufferfishEntity lePuffPuff = EntityType.PUFFERFISH.create( level ); final PufferfishEntity lePuffPuff = EntityType.PUFFERFISH.create( level );
if( lePuffPuff != null ) { if( lePuffPuff != null ) {
lePuffPuff.setPos( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); lePuffPuff.setPos( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );

View file

@ -71,7 +71,7 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
if( !explosion.initializeExplosion() ) return; if( !explosion.initializeExplosion() ) return;
explosion.finalizeExplosion(); explosion.finalizeExplosion();
if( explosionMode == Explosion.Mode.NONE ) return; if( explosionMode == Explosion.Mode.NONE || level.isClientSide() ) return;
final float throwPower = explosionPower + 4.0F; final float throwPower = explosionPower + 4.0F;
final int count = (int) Math.ceil( throwPower * throwPower * 3.5F ); final int count = (int) Math.ceil( throwPower * throwPower * 3.5F );
@ -94,14 +94,6 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
} }
} }
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "gravel" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
/** @return Attempts to damage this entity; returns true if the hit was successful. */ /** @return Attempts to damage this entity; returns true if the hit was successful. */
@Override @Override
public boolean hurt( DamageSource source, float amount ) { public boolean hurt( DamageSource source, float amount ) {
@ -111,4 +103,12 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
} }
return super.hurt( source, amount ); return super.hurt( source, amount );
} }
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "gravel" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
} }

View file

@ -8,6 +8,7 @@ import fathertoast.specialmobs.common.util.References;
import fathertoast.specialmobs.datagen.loot.LootTableBuilder; import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.ILivingEntityData;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.SpawnReason; import net.minecraft.entity.SpawnReason;
import net.minecraft.entity.ai.attributes.AttributeModifierMap; import net.minecraft.entity.ai.attributes.AttributeModifierMap;
@ -19,6 +20,7 @@ import net.minecraft.util.SoundEvents;
import net.minecraft.world.IServerWorld; import net.minecraft.world.IServerWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
@ -72,27 +74,38 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
protected void makeVariantExplosion( float explosionPower ) { protected void makeVariantExplosion( float explosionPower ) {
ExplosionHelper.explode( this, explosionPower, false, false ); ExplosionHelper.explode( this, explosionPower, false, false );
if( !(level instanceof IServerWorld) ) return;
final int babiesToSpawn = extraBabies + (int) (explosionPower * explosionPower) / 2; final int babiesToSpawn = extraBabies + (int) (explosionPower * explosionPower) / 2;
ILivingEntityData groupData = null;
for( int i = 0; i < babiesToSpawn; i++ ) { for( int i = 0; i < babiesToSpawn; i++ ) {
groupData = spawnBaby( explosionPower / 3.0F, groupData );
}
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
}
/** Helper method to simplify spawning babies. */
@Nullable
private ILivingEntityData spawnBaby( float speed, @Nullable ILivingEntityData groupData ) {
final MiniCreeperEntity baby = MiniCreeperEntity.ENTITY_TYPE.get().create( level ); final MiniCreeperEntity baby = MiniCreeperEntity.ENTITY_TYPE.get().create( level );
if( baby == null ) continue; if( baby == null ) return groupData;
baby.copyPosition( this ); baby.copyPosition( this );
baby.yHeadRot = yRot; baby.yHeadRot = yRot;
baby.yBodyRot = yRot; baby.yBodyRot = yRot;
baby.finalizeSpawn( (IServerWorld) level, level.getCurrentDifficultyAt( blockPosition() ), SpawnReason.MOB_SUMMONED, null, null ); groupData = baby.finalizeSpawn( (IServerWorld) level, level.getCurrentDifficultyAt( blockPosition() ),
SpawnReason.MOB_SUMMONED, groupData, null );
baby.setTarget( getTarget() ); baby.setTarget( getTarget() );
if( isPowered() ) baby.getEntityData().set( DATA_IS_POWERED, true ); if( isPowered() ) baby.getEntityData().set( DATA_IS_POWERED, true );
baby.setDeltaMovement( baby.setDeltaMovement(
(random.nextDouble() - 0.5) * explosionPower / 3.0, (random.nextDouble() - 0.5) * speed,
0.3 + 0.3 * random.nextDouble(), // Used to cause floor clip bug; remove if it happens again 0.3 + 0.3 * random.nextDouble(), // Used to cause floor clip bug; remove if it happens again
(random.nextDouble() - 0.5) * explosionPower / 3.0 ); (random.nextDouble() - 0.5) * speed );
baby.setOnGround( false ); baby.setOnGround( false );
level.addFreshEntity( baby ); level.addFreshEntity( baby );
} return groupData;
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
} }
/** Override to save data to this entity's NBT data. */ /** Override to save data to this entity's NBT data. */

View file

@ -81,6 +81,19 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
/** Override to change this entity's AI goals. */ /** Override to change this entity's AI goals. */
protected void registerVariantGoals() { } protected void registerVariantGoals() { }
/** Called to melee attack the target. */
@Override
public boolean doHurtTarget( Entity target ) {
if( super.doHurtTarget( target ) ) {
onVariantAttack( target );
return true;
}
return false;
}
/** Override to apply effects when this entity hits a target with a melee attack. */
protected void onVariantAttack( Entity target ) { }
/** Called to perform this creeper's explosion 'attack'. */ /** Called to perform this creeper's explosion 'attack'. */
@Override @Override
protected void explodeCreeper() { protected void explodeCreeper() {
@ -187,6 +200,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
if( explodesWhileBurning() ) clearFire(); if( explodesWhileBurning() ) clearFire();
} }
/** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
@Nullable @Nullable
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason, public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) { @Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
@ -289,16 +303,6 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
getSpecialData().tick(); getSpecialData().tick();
} }
// // Called to attack the target.
// @Override
// public boolean attackEntityAsMob( Entity target ) {
// if( super.attackEntityAsMob( target ) ) {
// onTypeAttack( target );
// return true;
// }
// return false;
// }
/** @return The eye height of this entity when standing. */ /** @return The eye height of this entity when standing. */
@Override @Override
protected float getStandingEyeHeight( Pose pose, EntitySize size ) { protected float getStandingEyeHeight( Pose pose, EntitySize size ) {

View file

@ -97,6 +97,19 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
// TODO variant shooting // TODO variant shooting
/** Called to melee attack the target. */
@Override
public boolean doHurtTarget( Entity target ) {
if( super.doHurtTarget( target ) ) {
onVariantAttack( target );
return true;
}
return false;
}
/** 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. */ /** Override to save data to this entity's NBT data. */
public void addVariantSaveData( CompoundNBT saveTag ) { } public void addVariantSaveData( CompoundNBT saveTag ) { }
@ -120,12 +133,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
entityData.define( IS_BABY, false ); entityData.define( IS_BABY, false );
} }
@Override /** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
super.populateDefaultEquipmentSlots( difficulty );
setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( Items.BOW ) );
}
@Nullable @Nullable
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason, public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) { @Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
@ -134,6 +142,15 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
return groupData; return groupData;
} }
/** Called during spawn finalization to set starting equipment. */
@Override
protected void populateDefaultEquipmentSlots( DifficultyInstance difficulty ) {
super.populateDefaultEquipmentSlots( difficulty );
if( random.nextDouble() < 0.05 ) { //TODO config
setItemSlot( EquipmentSlotType.MAINHAND, new ItemStack( Items.IRON_SWORD ) );
}
}
/** Called to change */ /** Called to change */
@Override @Override
public void reassessWeaponGoal() { public void reassessWeaponGoal() {
@ -205,7 +222,7 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
public void setBaby( boolean value ) { public void setBaby( boolean value ) {
getEntityData().set( IS_BABY, value ); getEntityData().set( IS_BABY, value );
if( level != null && !level.isClientSide ) { if( level != null && !level.isClientSide ) {
ModifiableAttributeInstance attributeInstance = getAttribute( Attributes.MOVEMENT_SPEED ); final ModifiableAttributeInstance attributeInstance = getAttribute( Attributes.MOVEMENT_SPEED );
//noinspection ConstantConditions //noinspection ConstantConditions
attributeInstance.removeModifier( BABY_SPEED_BOOST ); attributeInstance.removeModifier( BABY_SPEED_BOOST );
if( value ) { if( value ) {
@ -279,16 +296,6 @@ public class _SpecialSkeletonEntity extends AbstractSkeletonEntity implements IS
getSpecialData().tick(); getSpecialData().tick();
} }
// // Called to attack the target.
// @Override
// public boolean attackEntityAsMob( Entity target ) {
// if( super.attackEntityAsMob( target ) ) {
// onTypeAttack( target );
// return true;
// }
// return false;
// }
/** @return The eye height of this entity when standing. */ /** @return The eye height of this entity when standing. */
@Override @Override
protected float getStandingEyeHeight( Pose pose, EntitySize size ) { protected float getStandingEyeHeight( Pose pose, EntitySize size ) {

View file

@ -0,0 +1,68 @@
package fathertoast.specialmobs.common.entity.spider;
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 net.minecraftforge.fml.RegistryObject;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class BabySpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.TypeHolder
public static RegistryObject<EntityType<BabySpiderEntity>> ENTITY_TYPE;
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.6F, 0.4F );
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.DISABLED );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.multAttribute( Attributes.MAX_HEALTH, 0.25 )
.addAttribute( Attributes.ATTACK_DAMAGE, -1.0 )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Baby Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
loot.addCommonDrop( "common", Items.STRING, 1 );
}
@SpecialMob.Constructor
public BabySpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 0.4F );
getSpecialData().rangedAttackDamage -= 1.0F;
getSpecialData().rangedAttackMaxRange = 0.0F;
xpReward = 1;
}
//--------------- Variant-Specific Implementations ----------------
// None
}

View file

@ -0,0 +1,91 @@
package fathertoast.specialmobs.common.entity.spider;
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.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 DesertSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 0.95F, 0.8F );
return new BestiaryInfo( 0xE6DDAC );
//TODO theme - desert
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 4.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Desert Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.LEATHER );
}
@SpecialMob.Constructor
public DesertSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 0.8F );
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 ) {
final LivingEntity livingTarget = (LivingEntity) target;
final int duration = MobHelper.getDebuffDuration( level.getDifficulty() );
if( true ) { //TODO config
livingTarget.addEffect( new EffectInstance( Effects.CONFUSION, duration, 0 ) );
}
livingTarget.addEffect( new EffectInstance( Effects.BLINDNESS, duration, 0 ) );
livingTarget.addEffect( new EffectInstance( Effects.MOVEMENT_SLOWDOWN, duration, 2 ) );
livingTarget.addEffect( new EffectInstance( Effects.DAMAGE_RESISTANCE, duration, -3 ) ); // 40% inc damage taken
}
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "desert" ),
GET_TEXTURE_PATH( "desert_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,77 @@
package fathertoast.specialmobs.common.entity.spider;
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
import fathertoast.specialmobs.common.bestiary.SpecialMob;
import fathertoast.specialmobs.common.entity.ai.SpecialLeapAtTargetGoal;
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.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class FlyingSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0x6388B2 );
//TODO theme - mountain
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Flying Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.FEATHER );
}
@SpecialMob.Constructor
public FlyingSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setFallDamageMultiplier( 0.0F );
xpReward += 2;
}
//--------------- Variant-Specific Implementations ----------------
/** Override to change this entity's AI goals. */
@Override
protected void registerVariantGoals() {
goalSelector.addGoal( 3, new SpecialLeapAtTargetGoal(
this, 10, 6.0F, 12.0F, 2.0F, 2.0F ) );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "flying" ),
GET_TEXTURE_PATH( "flying_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,63 @@
package fathertoast.specialmobs.common.entity.spider;
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 GiantSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 1.9F, 1.3F );
return new BestiaryInfo( 0xA80E0E );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 16.0 )
.addAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Giant Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addGuaranteedDrop( "base", Items.STRING, 2 );
}
@SpecialMob.Constructor
public GiantSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
getSpecialData().rangedAttackDamage += 1.0F;
xpReward += 1;
}
//--------------- Variant-Specific Implementations ----------------
// None
}

View file

@ -0,0 +1,152 @@
package fathertoast.specialmobs.common.entity.spider;
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.AttributeModifier;
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.player.PlayerEntity;
import net.minecraft.item.Food;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvents;
import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.UUID;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class HungrySpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 1.9F, 1.3F );
return new BestiaryInfo( 0x799C65 );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 4.0 )
.addAttribute( Attributes.ATTACK_DAMAGE, -1.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Hungry Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addCommonDrop( "common", Items.BONE );
loot.addUncommonDrop( "uncommon", Items.APPLE, Items.BEETROOT, Items.ROTTEN_FLESH, Items.CHICKEN, Items.RABBIT, Items.COOKIE );
}
@SpecialMob.Constructor
public HungrySpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.5F );
getSpecialData().setRegenerationTime( 40 );
getSpecialData().rangedAttackMaxRange = 0.0F;
xpReward += 2;
}
//--------------- Variant-Specific Implementations ----------------
/** The damage boost to apply from growth level. */
private static final AttributeModifier DAMAGE_BOOST = new AttributeModifier( UUID.fromString( "70457CAB-AA09-4E1C-B44B-99DD4A2A836D" ),
"Feeding damage boost", 1.0, AttributeModifier.Operation.ADDITION );
/** The health boost to apply from max health stacks. */
private static final AttributeModifier HEALTH_BOOST = new AttributeModifier( UUID.fromString( "D22A70EF-7C71-4BC5-8B23-7045728FD84F" ),
"Feeding health boost", 2.0, AttributeModifier.Operation.ADDITION );
/** The level of increased attack damage gained. */
private int growthLevel;
/** The level of increased max health gained. */
private int maxHealthStacks;
/** Override to apply effects when this entity hits a target with a melee attack. */
@Override
protected void onVariantAttack( Entity target ) {
if( !level.isClientSide() && target instanceof PlayerEntity && ForgeEventFactory.getMobGriefingEvent( level, this ) ) {
final ItemStack food = MobHelper.stealRandomFood( (PlayerEntity) target );
if( !food.isEmpty() ) {
final float previousHealth = getMaxHealth();
if( maxHealthStacks < 32 ) maxHealthStacks++;
if( growthLevel < 7 ) growthLevel++;
updateFeedingLevels();
setHealth( getHealth() + getMaxHealth() - previousHealth );
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 );
}
}
}
private void updateFeedingLevels() {
if( level != null && !level.isClientSide ) {
final ModifiableAttributeInstance health = getAttribute( Attributes.MAX_HEALTH );
final ModifiableAttributeInstance damage = getAttribute( Attributes.ATTACK_DAMAGE );
//noinspection ConstantConditions
health.removeModifier( HEALTH_BOOST.getId() );
//noinspection ConstantConditions
damage.removeModifier( DAMAGE_BOOST.getId() );
if( maxHealthStacks > 0 ) {
// Health, in particular, must be permanent to avoid health getting throttled on reload
health.addPermanentModifier( new AttributeModifier( HEALTH_BOOST.getId(), HEALTH_BOOST.getName(),
HEALTH_BOOST.getAmount() * maxHealthStacks, HEALTH_BOOST.getOperation() ) );
}
if( growthLevel > 0 ) {
damage.addPermanentModifier( new AttributeModifier( DAMAGE_BOOST.getId(), DAMAGE_BOOST.getName(),
DAMAGE_BOOST.getAmount() * growthLevel, DAMAGE_BOOST.getOperation() ) );
}
}
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_HEALTH_STACKS, (byte) maxHealthStacks );
saveTag.putByte( References.TAG_GROWTH_LEVEL, (byte) growthLevel );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_HEALTH_STACKS, References.NBT_TYPE_NUMERICAL ) )
maxHealthStacks = saveTag.getByte( References.TAG_HEALTH_STACKS );
if( saveTag.contains( References.TAG_GROWTH_LEVEL, References.NBT_TYPE_NUMERICAL ) )
growthLevel = saveTag.getByte( References.TAG_GROWTH_LEVEL );
updateFeedingLevels();
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "hungry" ),
GET_TEXTURE_PATH( "hungry_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,156 @@
package fathertoast.specialmobs.common.entity.spider;
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.ILivingEntityData;
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.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.world.IServerWorld;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class MotherSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
entityType.sized( 1.8F, 1.2F );
return new BestiaryInfo( 0xB300B3 );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 16.0 )
.addAttribute( Attributes.ATTACK_DAMAGE, 3.0 )
.addAttribute( Attributes.ARMOR, 6.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Mother Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addUncommonDrop( "uncommon", Items.SPIDER_SPAWN_EGG );
}
@SpecialMob.Constructor
public MotherSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
getSpecialData().setBaseScale( 1.4F );
getSpecialData().setRegenerationTime( 30 );
getSpecialData().rangedAttackDamage += 1.5F;
xpReward += 1;
babies = 2 + random.nextInt( 3 );
extraBabies = 2 + random.nextInt( 3 );
}
//--------------- Variant-Specific Implementations ----------------
/** The number of babies spawned on death. */
private int babies;
/** The number of extra babies that can be spawned from hits. */
private int extraBabies;
/** @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 ) ) {
// Spawn babies when damaged
if( extraBabies > 0 && amount > 1.0F && level instanceof IServerWorld && random.nextFloat() < 0.33F ) {
extraBabies--;
spawnBaby( 0.66F, null );
}
return true;
}
return false;
}
/** Called each tick to update this entity while it's dead. */
@Override
protected void tickDeath() {
if( deathTime == 19 && level instanceof IServerWorld ) { // At 19, the entity will be immediately removed upon call to super method
// Spawn babies on death
final int babiesToSpawn = babies + extraBabies;
ILivingEntityData groupData = null;
for( int i = 0; i < babiesToSpawn; i++ ) {
groupData = spawnBaby( 0.33F, groupData );
}
playSound( SoundEvents.EGG_THROW, 1.0F, 2.0F / (random.nextFloat() * 0.4F + 0.8F) );
}
super.tickDeath();
}
/** Helper method to simplify spawning babies. */
@Nullable
private ILivingEntityData spawnBaby( float speed, @Nullable ILivingEntityData groupData ) {
final BabySpiderEntity baby = BabySpiderEntity.ENTITY_TYPE.get().create( level );
if( baby == null ) return groupData;
baby.copyPosition( this );
baby.yHeadRot = yRot;
baby.yBodyRot = yRot;
groupData = baby.finalizeSpawn( (IServerWorld) level, level.getCurrentDifficultyAt( blockPosition() ),
SpawnReason.MOB_SUMMONED, groupData, null );
baby.setTarget( getTarget() );
baby.setDeltaMovement(
(random.nextDouble() - 0.5) * speed,
0.2 + 0.5 * random.nextDouble(), // Used to cause floor clip bug; remove if it happens again
(random.nextDouble() - 0.5) * speed );
baby.setOnGround( false );
level.addFreshEntity( baby );
return groupData;
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_BABIES, (byte) babies );
saveTag.putByte( References.TAG_EXTRA_BABIES, (byte) extraBabies );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_BABIES, References.NBT_TYPE_NUMERICAL ) )
babies = saveTag.getByte( References.TAG_BABIES );
if( saveTag.contains( References.TAG_EXTRA_BABIES, References.NBT_TYPE_NUMERICAL ) )
extraBabies = saveTag.getByte( References.TAG_EXTRA_BABIES );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "mother" ),
GET_TEXTURE_PATH( "mother_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,84 @@
package fathertoast.specialmobs.common.entity.spider;
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.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 PaleSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xDED4C6 );
//TODO theme - ice
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.ARMOR, 15.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Pale Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addSemicommonDrop( "semicommon", Items.FERMENTED_SPIDER_EYE );
}
@SpecialMob.Constructor
public PaleSpiderEntity( EntityType<? extends _SpecialSpiderEntity> 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 ) {
final LivingEntity livingTarget = (LivingEntity) target;
final int duration = MobHelper.getDebuffDuration( level.getDifficulty() );
livingTarget.addEffect( new EffectInstance( Effects.WEAKNESS, duration, 0 ) );
livingTarget.addEffect( new EffectInstance( Effects.DIG_SLOWDOWN, duration, 1 ) );
}
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "pale" ),
GET_TEXTURE_PATH( "pale_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,79 @@
package fathertoast.specialmobs.common.entity.spider;
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.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 PoisonSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0x0C424E );
//TODO theme - forest
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return _SpecialSpiderEntity.createAttributes();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Venomous Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addUncommonDrop( "uncommon", Items.SPIDER_EYE );
}
@SpecialMob.Constructor
public PoisonSpiderEntity( EntityType<? extends _SpecialSpiderEntity> 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 ) {
final LivingEntity livingTarget = (LivingEntity) target;
final int duration = MobHelper.getDebuffDuration( level.getDifficulty() );
livingTarget.addEffect( new EffectInstance( Effects.POISON, duration ) );
}
}
private static final ResourceLocation[] TEXTURES = {
new ResourceLocation( "textures/entity/spider/cave_spider.png" ),
new ResourceLocation( "textures/entity/spider_eyes.png" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,119 @@
package fathertoast.specialmobs.common.entity.spider;
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.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.monster.SpiderEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class WebSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xE7E7E7, BestiaryInfo.BaseWeight.LOW );
//TODO theme - forest
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.MAX_HEALTH, 4.0 )
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Weaver",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addUncommonDrop( "uncommon", Blocks.COBWEB );
}
@SpecialMob.Constructor
public WebSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
xpReward += 2;
webCount = 2 + random.nextInt( 5 );
}
//--------------- Variant-Specific Implementations ----------------
/** The number of cobwebs this spider can place. */
private int webCount;
/** Override to apply effects when this entity hits a target with a melee attack. */
@Override
protected void onVariantAttack( Entity target ) {
if( !level.isClientSide() && webCount > 0 && target instanceof LivingEntity && !(target instanceof SpiderEntity) ) {
final BlockPos pos = target.blockPosition();
if( !tryPlaceWeb( pos ) && target.getBbHeight() > 1.0F ) {
tryPlaceWeb( pos.above() );
}
}
}
/** Called when this entity dies to add drops regardless of loot table. */
@Override
protected void dropCustomDeathLoot( DamageSource source, int looting, boolean killedByPlayer ) {
super.dropCustomDeathLoot( source, looting, killedByPlayer );
tryPlaceWeb( blockPosition() );
}
/** @return Attempts to place a cobweb at the given position and returns true if successful. */
private boolean tryPlaceWeb( BlockPos pos ) {
if( level.getBlockState( pos ).getMaterial().isReplaceable() ) {
level.setBlock( pos, Blocks.COBWEB.defaultBlockState(), References.SET_BLOCK_FLAGS );
webCount--;
return true;
}
return false;
}
/** Override to save data to this entity's NBT data. */
@Override
public void addVariantSaveData( CompoundNBT saveTag ) {
saveTag.putByte( References.TAG_AMMO, (byte) webCount );
}
/** Override to load data from this entity's NBT data. */
@Override
public void readVariantSaveData( CompoundNBT saveTag ) {
if( saveTag.contains( References.TAG_AMMO, References.NBT_TYPE_NUMERICAL ) )
webCount = saveTag.getByte( References.TAG_AMMO );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "web" ),
GET_TEXTURE_PATH( "web_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,87 @@
package fathertoast.specialmobs.common.entity.spider;
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.potion.EffectInstance;
import net.minecraft.potion.EffectType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SpecialMob
public class WitchSpiderEntity extends _SpecialSpiderEntity {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xDD0E0E, BestiaryInfo.BaseWeight.LOW );
//TODO theme - forest
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return AttributeHelper.of( _SpecialSpiderEntity.createAttributes() )
.addAttribute( Attributes.ARMOR, 15.0 )
.build();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Witch Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void buildLootTable( LootTableBuilder loot ) {
addBaseLoot( loot );
loot.addLootTable( "common", EntityType.WITCH.getDefaultLootTable() );
}
@SpecialMob.Constructor
public WitchSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
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 ) {
((LivingEntity) target).addEffect( MobHelper.nextWitchSpiderEffect( random, level, true ) );
MobHelper.stealBuffEffect( this, (LivingEntity) target );
}
}
/** @return True if the effect can be applied to this entity. */
@Override
public boolean canBeAffected( EffectInstance effect ) {
// Witch spider is immune to debuffs
return effect.getEffect().getCategory() != EffectType.HARMFUL && super.canBeAffected( effect );
}
private static final ResourceLocation[] TEXTURES = {
GET_TEXTURE_PATH( "witch" ),
GET_TEXTURE_PATH( "witch_eyes" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
}

View file

@ -0,0 +1,231 @@
package fathertoast.specialmobs.common.entity.spider;
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.AttributeModifierMap;
import net.minecraft.entity.monster.SpiderEntity;
import net.minecraft.entity.player.PlayerEntity;
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.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 _SpecialSpiderEntity extends SpiderEntity implements ISpecialMob<_SpecialSpiderEntity> {
//--------------- Static Special Mob Hooks ----------------
@SpecialMob.BestiaryInfoSupplier
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
return new BestiaryInfo( 0xA80E0E );
}
@SpecialMob.AttributeCreator
public static AttributeModifierMap.MutableAttribute createAttributes() {
return SpiderEntity.createAttributes();
}
@SpecialMob.LanguageProvider
public static String[] getTranslations( String langKey ) {
return References.translations( langKey, "Spider",
"", "", "", "", "", "" );//TODO
}
@SpecialMob.LootTableProvider
public static void addBaseLoot( LootTableBuilder loot ) {
loot.addLootTable( "main", EntityType.SPIDER.getDefaultLootTable() );
}
@SpecialMob.Constructor
public _SpecialSpiderEntity( EntityType<? extends _SpecialSpiderEntity> entityType, World world ) {
super( entityType, world );
specialData.initialize();
}
//--------------- Variant-Specific Breakouts ----------------
/** 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 to melee attack the target. */
@Override
public boolean doHurtTarget( Entity target ) {
if( super.doHurtTarget( target ) ) {
onVariantAttack( target );
return true;
}
return false;
}
/** 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( _SpecialSpiderEntity.class, DataSerializers.FLOAT );
/** Called from the Entity.class constructor to define data watcher variables. */
@Override
protected void defineSynchedData() {
super.defineSynchedData();
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
}
/** Called 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<_SpecialSpiderEntity> specialData;
/** @return This mob's special data. */
@Override
public SpecialMobData<_SpecialSpiderEntity> getSpecialData() { return specialData; }
/** @return The experience that should be dropped by this entity. */
@Override
public final int getExperience() { return xpReward; }
/** Sets the experience that should be dropped by this entity. */
@Override
public final void setExperience( int xp ) { xpReward = xp; }
static ResourceLocation GET_TEXTURE_PATH( String type ) {
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "spider/" + type + ".png" );
}
private static final ResourceLocation[] TEXTURES = {
new ResourceLocation( "textures/entity/spider/spider.png" ),
new ResourceLocation( "textures/entity/spider_eyes.png" )
};
/** @return All default textures for this entity. */
@Override
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
//TODO--------------- 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 specialData.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( specialData.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 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 );
}
}

View file

@ -62,7 +62,15 @@ public final class References {
public static final String TAG_IS_BABY = "IsBaby"; public static final String TAG_IS_BABY = "IsBaby";
// Spawner mobs TODO drowning creeper pufferfish cap? // Spawner mobs TODO drowning creeper pufferfish cap?
public static final String TAG_EXTRA_BABIES = "ExtraBabies"; // Splitting Creepers public static final String TAG_BABIES = "Babies"; // Mother Spd
public static final String TAG_EXTRA_BABIES = "ExtraBabies"; // Splitting Crp, Mother Spd
// Growing mobs
public static final String TAG_GROWTH_LEVEL = "GrowthLevel"; // Hungry Spd
public static final String TAG_HEALTH_STACKS = "HealthStacks"; // Hungry Spd
// Misc.
public static final String TAG_AMMO = "Ammo"; // Web Spd
//--------------- INTERNATIONALIZATION ---------------- //--------------- INTERNATIONALIZATION ----------------

View file

@ -6,7 +6,7 @@ issueTrackerURL = "https://github.com/FatherToast/SpecialMobs/issues/"
[[mods]] [[mods]]
logoFile = "banner.png" logoFile = "banner.png"
authors = "Father Toast" authors = "Father Toast"
credits = "Sarinsa, Mother Toast & Baby Toast" credits = "Sarinsa.instance().getCredits().toString(), Tutta (glorious textures), Mother Toast & Baby Toast"
version = "${file.jarVersion}" version = "${file.jarVersion}"
displayName = "Special Mobs" displayName = "Special Mobs"
modId = "specialmobs" modId = "specialmobs"
@ -21,7 +21,7 @@ Download: https://www.curseforge.com/members/fathertoast/projects/
Source: https://github.com/FatherToast/ Source: https://github.com/FatherToast/
Discussion: https://discord.gg/GFTzTdX/ Discussion: https://discord.gg/GFTzTdX
''' '''
[[dependencies.deadlyworld]] [[dependencies.deadlyworld]]