mirror of
https://github.com/FatherToast/SpecialMobs.git
synced 2025-08-30 14:01:25 +00:00
Config implementation & bestiary rework
This commit is contained in:
parent
86ef90e201
commit
22cfb5616b
243 changed files with 4971 additions and 4198 deletions
|
@ -10,7 +10,6 @@ import fathertoast.specialmobs.common.entity.witherskeleton.NinjaWitherSkeletonE
|
|||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.RenderTypeLookup;
|
||||
import net.minecraft.client.renderer.entity.SpriteRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
|
@ -58,12 +57,12 @@ public class ClientRegister {
|
|||
registerSpeciesRenderer( NinjaSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new );
|
||||
registerSpeciesRenderer( NinjaWitherSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new );
|
||||
registerSpeciesRenderer( CorporealShiftGhastEntity.SPECIES, CorporealShiftGhastRenderer::new );
|
||||
|
||||
|
||||
// Other
|
||||
registerSpriteRenderer( SMEntities.CORPOREAL_FIREBALL.get(), game, 3.0F, true );
|
||||
}
|
||||
|
||||
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 ) {
|
||||
RenderingRegistry.registerEntityRenderingHandler( family.vanillaReplacement.entityType.get(), renderFactory );
|
||||
for( MobFamily.Species<? extends T> species : family.variants )
|
||||
registerSpeciesRenderer( species, renderFactory );
|
||||
|
@ -72,9 +71,9 @@ public class ClientRegister {
|
|||
private static <T extends LivingEntity> void registerSpeciesRenderer( MobFamily.Species<T> species, IRenderFactory<? super T> renderFactory ) {
|
||||
RenderingRegistry.registerEntityRenderingHandler( species.entityType.get(), renderFactory );
|
||||
}
|
||||
|
||||
private static <T extends Entity & IRendersAsItem> void registerSpriteRenderer(EntityType<T> entityType, Supplier<Minecraft> minecraftSupplier, float scale, boolean fullBright) {
|
||||
|
||||
private static <T extends Entity & IRendersAsItem> void registerSpriteRenderer( EntityType<T> entityType, Supplier<Minecraft> minecraftSupplier, float scale, boolean fullBright ) {
|
||||
ItemRenderer itemRenderer = minecraftSupplier.get().getItemRenderer();
|
||||
RenderingRegistry.registerEntityRenderingHandler(entityType, (renderManager) -> new SpriteRenderer<>(renderManager, itemRenderer, scale, fullBright));
|
||||
RenderingRegistry.registerEntityRenderingHandler( entityType, ( renderManager ) -> new SpriteRenderer<>( renderManager, itemRenderer, scale, fullBright ) );
|
||||
}
|
||||
}
|
|
@ -1,8 +1,30 @@
|
|||
package fathertoast.specialmobs.common.bestiary;
|
||||
|
||||
import fathertoast.specialmobs.common.config.util.AttributeEntry;
|
||||
import fathertoast.specialmobs.common.config.util.AttributeList;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
import fathertoast.specialmobs.common.config.util.RegistryEntryList;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.potion.Effect;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class serves solely to store data for mob species in an organized way, providing builder methods as applicable.
|
||||
* The bulk of bestiary info is default config settings.
|
||||
*/
|
||||
public class BestiaryInfo {
|
||||
|
||||
public enum BaseWeight {
|
||||
public enum DefaultWeight {
|
||||
DEFAULT( 600 ),
|
||||
DISABLED( 0 ),
|
||||
LOWEST( DEFAULT.value / 8 ),
|
||||
|
@ -12,103 +34,555 @@ public class BestiaryInfo {
|
|||
|
||||
public final int value;
|
||||
|
||||
BaseWeight( int v ) { value = v; }
|
||||
DefaultWeight( int v ) { value = v; }
|
||||
}
|
||||
|
||||
//TODO default themes
|
||||
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_FIRE = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "mesa", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetDimension( DimensionType.NETHER, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "ice", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "frozen", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "cold", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "taiga_cold", BestiaryInfo.BASE_WEIGHT_RARE )
|
||||
// );
|
||||
//
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_ICE = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "ice", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "frozen", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "cold", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "taiga_cold", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "mesa", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetDimension( DimensionType.NETHER, BestiaryInfo.BASE_WEIGHT_RARE )
|
||||
// );
|
||||
//
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_FOREST = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "swamp", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "forest", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "birch_forest", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "roofed_forest", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "jungle", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "taiga", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "redwood_taiga", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "ice", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "stone", BestiaryInfo.BASE_WEIGHT_RARE )
|
||||
// );
|
||||
//
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_MOUNTAIN = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "extreme", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "smaller_extreme", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "mesa", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "ice_mountains", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "stone", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "plains", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "swamp", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "beach", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "cold_beach", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "ice_flats", BestiaryInfo.BASE_WEIGHT_RARE )
|
||||
// );
|
||||
//
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_WATER = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "swamp", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.BEACH, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.DEEP_OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.FROZEN_OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_RARE ),
|
||||
// new TargetEnvironment.TargetDimension( DimensionType.NETHER, 0 )
|
||||
// );
|
||||
//
|
||||
// public static final EnvironmentListConfig DEFAULT_THEME_FISHING = new EnvironmentListConfig(
|
||||
// new TargetEnvironment.TargetBiomeGroup( "swamp", BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.BEACH, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.DEEP_OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
// new TargetEnvironment.TargetBiome( Biomes.FROZEN_OCEAN, BestiaryInfo.BASE_WEIGHT_COMMON ),
|
||||
//
|
||||
// new TargetEnvironment.TargetBiomeGroup( "desert", BestiaryInfo.BASE_WEIGHT_UNCOMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "savanna", BestiaryInfo.BASE_WEIGHT_UNCOMMON ),
|
||||
// new TargetEnvironment.TargetBiomeGroup( "mesa", BestiaryInfo.BASE_WEIGHT_UNCOMMON )
|
||||
// );
|
||||
|
||||
// These can be set in the entity class to change these default values.
|
||||
//public EnvironmentListConfig weightExceptions = new EnvironmentListConfig( );
|
||||
public enum Theme {
|
||||
NONE,
|
||||
FIRE, ICE,
|
||||
DESERT, WATER,
|
||||
FOREST, MOUNTAIN,
|
||||
FISHING
|
||||
}
|
||||
|
||||
/** The spot color for spawn eggs of this species. The base color is determined by the family. */
|
||||
public final int eggSpotsColor;
|
||||
public final BaseWeight weight;
|
||||
/** The base render scale of this species. */
|
||||
public final float baseScale;
|
||||
|
||||
public BestiaryInfo( int eggColor ) { this( eggColor, BaseWeight.DEFAULT ); }
|
||||
/** The default species weight. */
|
||||
public final DefaultWeight defaultWeight;
|
||||
/** The species theme; determines default environment weight exceptions. */
|
||||
public final Theme theme;
|
||||
/** The default species attribute differences compared to their vanilla counterpart. */
|
||||
public final AttributeList defaultAttributes;
|
||||
|
||||
public BestiaryInfo( int eggColor, BaseWeight baseWeight ) {
|
||||
eggSpotsColor = eggColor;
|
||||
weight = baseWeight;
|
||||
/** The default texture. */
|
||||
public final ResourceLocation texture;
|
||||
/** The default glowing eyes texture. Not applicable for ghasts or families normally rendered at max brightness. */
|
||||
public final ResourceLocation eyesTexture;
|
||||
/**
|
||||
* The default overlay texture.
|
||||
* Generally only applicable for bipedal mobs, though this is used as the "shooting" texture for ghasts.
|
||||
*/
|
||||
public final ResourceLocation overlayTexture;
|
||||
|
||||
// Special Mob Data defaults
|
||||
public final int experience;
|
||||
public final int healTime;
|
||||
public final double fallDamageMultiplier;
|
||||
public final boolean isImmuneToFire;
|
||||
public final boolean isImmuneToBurning;
|
||||
public final boolean canBreatheInWater;
|
||||
public final boolean ignoreWaterPush;
|
||||
public final boolean isDamagedByWater;
|
||||
public final boolean allowLeashing;
|
||||
public final boolean ignorePressurePlates;
|
||||
public final RegistryEntryList<Block> immuneToStickyBlocks;
|
||||
public final RegistryEntryList<Effect> immuneToPotions;
|
||||
public final double rangedAttackDamage;
|
||||
public final double rangedAttackSpread;
|
||||
public final double rangedWalkSpeed;
|
||||
public final int rangedAttackCooldown;
|
||||
public final int rangedAttackMaxCooldown;
|
||||
public final double rangedAttackMaxRange;
|
||||
|
||||
|
||||
//--------------- Builder Implementation ----------------
|
||||
|
||||
public static BestiaryInfo.Builder of( MobFamily.Species<?> species, EntityType.Builder<?> typeBuilder ) {
|
||||
return new Builder( species, typeBuilder );
|
||||
}
|
||||
|
||||
public BestiaryInfo setTheme() {
|
||||
return this;//TODO theme builder
|
||||
private BestiaryInfo( int eggColor, float scale, DefaultWeight weight, Theme spawnTheme, List<AttributeEntry> attributes,
|
||||
ResourceLocation tex, ResourceLocation eyeTex, ResourceLocation ovrTex,
|
||||
int xp, int regen, double fallDmg, boolean fireImm, boolean burnImm, boolean drownImm, boolean pushImm,
|
||||
boolean waterDmg, boolean leash, boolean plateImm, Block[] blockImm, Effect[] effectImm,
|
||||
double raDmg, double raVar, double raSpd, int raCD, int raMCD, double raRng ) {
|
||||
eggSpotsColor = eggColor;
|
||||
baseScale = scale;
|
||||
|
||||
defaultWeight = weight;
|
||||
theme = spawnTheme;
|
||||
defaultAttributes = new AttributeList( attributes );
|
||||
|
||||
texture = tex;
|
||||
eyesTexture = eyeTex;
|
||||
overlayTexture = ovrTex;
|
||||
|
||||
experience = xp;
|
||||
healTime = regen;
|
||||
fallDamageMultiplier = fallDmg;
|
||||
isImmuneToFire = fireImm;
|
||||
isImmuneToBurning = burnImm;
|
||||
canBreatheInWater = drownImm;
|
||||
ignoreWaterPush = pushImm;
|
||||
isDamagedByWater = waterDmg;
|
||||
allowLeashing = leash;
|
||||
ignorePressurePlates = plateImm;
|
||||
immuneToStickyBlocks = new RegistryEntryList<>( ForgeRegistries.BLOCKS, blockImm );
|
||||
immuneToPotions = new RegistryEntryList<>( ForgeRegistries.POTIONS, effectImm );
|
||||
rangedAttackDamage = raDmg;
|
||||
rangedAttackSpread = raVar;
|
||||
rangedWalkSpeed = raSpd;
|
||||
rangedAttackCooldown = raCD;
|
||||
rangedAttackMaxCooldown = raMCD;
|
||||
rangedAttackMaxRange = raRng;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "UnusedReturnValue", "unused" } )
|
||||
public static final class Builder {
|
||||
|
||||
private final MobFamily.Species<?> owningSpecies;
|
||||
private final EntityType.Builder<?> entityTypeBuilder;
|
||||
|
||||
// Fields NOT inherited from vanilla replacement
|
||||
private boolean colorSet;
|
||||
private int eggSpotsColor;
|
||||
private DefaultWeight defaultWeight = DefaultWeight.DEFAULT;
|
||||
private Theme spawnTheme = Theme.NONE;
|
||||
private final List<AttributeEntry> attributes = new ArrayList<>();
|
||||
|
||||
// Fields inherited from vanilla replacement (technically also SM Data)
|
||||
private float baseScale = 1.0F;
|
||||
private ResourceLocation texture;
|
||||
private ResourceLocation eyesTexture;
|
||||
private ResourceLocation overlayTexture;
|
||||
|
||||
// Special Mob Data fields (also inherited)
|
||||
private int experience = -1;
|
||||
private int healTime;
|
||||
private double fallDamageMultiplier = 1.0;
|
||||
private boolean isImmuneToFire;
|
||||
private boolean isImmuneToBurning;
|
||||
private boolean canBreatheInWater;
|
||||
private boolean ignoreWaterPush;
|
||||
private boolean isDamagedByWater;
|
||||
private boolean allowLeashing;
|
||||
private boolean ignorePressurePlates;
|
||||
private final ArrayList<Block> immuneToStickyBlocks = new ArrayList<>();
|
||||
private final ArrayList<Effect> immuneToPotions = new ArrayList<>();
|
||||
private double rangedAttackDamage = -1.0;
|
||||
private double rangedAttackSpread = -1.0;
|
||||
private double rangedWalkSpeed = -1.0;
|
||||
private int rangedAttackCooldown = -1;
|
||||
private int rangedAttackMaxCooldown = -1;
|
||||
private double rangedAttackMaxRange = -1.0;
|
||||
|
||||
private Builder( MobFamily.Species<?> species, EntityType.Builder<?> typeBuilder ) {
|
||||
owningSpecies = species;
|
||||
entityTypeBuilder = typeBuilder;
|
||||
|
||||
// Special variants should copy many of the vanilla replacement's stats
|
||||
if( species.specialVariantName != null ) {
|
||||
final BestiaryInfo parent = species.family.vanillaReplacement.bestiaryInfo;
|
||||
|
||||
baseScale = parent.baseScale;
|
||||
texture = parent.texture;
|
||||
eyesTexture = parent.eyesTexture;
|
||||
overlayTexture = parent.overlayTexture;
|
||||
|
||||
experience = parent.experience;
|
||||
healTime = parent.healTime;
|
||||
fallDamageMultiplier = parent.fallDamageMultiplier;
|
||||
isImmuneToFire = parent.isImmuneToFire;
|
||||
isImmuneToBurning = parent.isImmuneToBurning;
|
||||
canBreatheInWater = parent.canBreatheInWater;
|
||||
ignoreWaterPush = parent.ignoreWaterPush;
|
||||
isDamagedByWater = parent.isDamagedByWater;
|
||||
allowLeashing = parent.allowLeashing;
|
||||
ignorePressurePlates = parent.ignorePressurePlates;
|
||||
immuneToStickyBlocks.addAll( parent.immuneToStickyBlocks.getEntries() );
|
||||
immuneToPotions.addAll( parent.immuneToPotions.getEntries() );
|
||||
|
||||
rangedAttackDamage = parent.rangedAttackDamage;
|
||||
rangedAttackSpread = parent.rangedAttackSpread;
|
||||
rangedWalkSpeed = parent.rangedWalkSpeed;
|
||||
rangedAttackCooldown = parent.rangedAttackCooldown;
|
||||
rangedAttackMaxCooldown = parent.rangedAttackMaxCooldown;
|
||||
rangedAttackMaxRange = parent.rangedAttackMaxRange;
|
||||
}
|
||||
}
|
||||
|
||||
BestiaryInfo build() {
|
||||
// Perform a little verification
|
||||
if( !colorSet )
|
||||
throw new IllegalStateException( "Species " + owningSpecies.name + " has not assigned egg spots color!" );
|
||||
if( experience < 0 )
|
||||
throw new IllegalStateException( "Family " + owningSpecies.family.name + " has not set the base experience value!" );
|
||||
|
||||
return new BestiaryInfo( eggSpotsColor, baseScale, defaultWeight, spawnTheme, attributes, texture, eyesTexture, overlayTexture,
|
||||
experience, healTime, fallDamageMultiplier, isImmuneToFire, isImmuneToBurning, canBreatheInWater, ignoreWaterPush, isDamagedByWater,
|
||||
allowLeashing, ignorePressurePlates, immuneToStickyBlocks.toArray( new Block[0] ), immuneToPotions.toArray( new Effect[0] ),
|
||||
rangedAttackDamage, rangedAttackSpread, rangedWalkSpeed, rangedAttackCooldown, rangedAttackMaxCooldown, rangedAttackMaxRange );
|
||||
}
|
||||
|
||||
|
||||
//--------------- Bestiary ----------------
|
||||
|
||||
/** Sets the species spawn egg spots color. This MUST be called or the build will throw an exception! */
|
||||
public Builder color( int eggColor ) {
|
||||
eggSpotsColor = eggColor;
|
||||
colorSet = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default weight. */
|
||||
public Builder weight( DefaultWeight weight ) {
|
||||
defaultWeight = weight;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default environment weight exceptions by theme. */
|
||||
public Builder theme( Theme theme ) {
|
||||
spawnTheme = theme;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Size ----------------
|
||||
|
||||
/** Sets the family base render size. Throws an exception if called for a special variant. */
|
||||
public Builder familySize( float renderScale ) {
|
||||
// Do NOT use for special variants; if the render scale is changed, the bounding box should match!
|
||||
if( owningSpecies.specialVariantName != null )
|
||||
throw new IllegalStateException( "Special variant " + owningSpecies.specialVariantName + " cannot set family render scale!" );
|
||||
baseScale = renderScale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species size - both render scale and bounding box dimensions. */
|
||||
public Builder size( float renderScale, float width, float height ) {
|
||||
baseScale = renderScale;
|
||||
entityTypeBuilder.sized( width, height );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Textures (Vanilla) ----------------
|
||||
|
||||
/** Sets the species default base, glowing eyes, and overlay textures. */
|
||||
public Builder vanillaTexturesAll( String tex, String eyeTex, String ovrTex ) {
|
||||
return vanillaBaseTexture( tex ).vanillaEyesTexture( eyeTex ).vanillaOverlayTexture( ovrTex );
|
||||
}
|
||||
|
||||
/** Sets the species default base and glowing eyes textures. Removes all other textures. */
|
||||
public Builder vanillaTextureWithEyes( String tex, String eyeTex ) {
|
||||
return vanillaBaseTexture( tex ).vanillaEyesTexture( eyeTex ).noOverlayTexture();
|
||||
}
|
||||
|
||||
/** Sets the species default base and overlay textures. Removes all other textures. */
|
||||
public Builder vanillaTextureWithOverlay( String tex, String ovrTex ) {
|
||||
return vanillaBaseTexture( tex ).noEyesTexture().vanillaOverlayTexture( ovrTex );
|
||||
}
|
||||
|
||||
/** Sets the species default base and animation (overlay) textures. Removes all other textures. */
|
||||
public Builder vanillaTextureWithAnimation( String tex, String aniTex ) { return vanillaTextureWithOverlay( tex, aniTex ); }
|
||||
|
||||
/** Sets the species default base texture. Removes all other textures. */
|
||||
public Builder vanillaTextureBaseOnly( String tex ) { return vanillaBaseTexture( tex ).noEyesTexture().noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base texture. */
|
||||
private Builder vanillaBaseTexture( String tex ) { return baseTexture( tex == null ? null : new ResourceLocation( tex ) ); }
|
||||
|
||||
/** Sets the species default glowing eyes texture. */
|
||||
private Builder vanillaEyesTexture( String eyeTex ) { return eyesTexture( eyeTex == null ? null : new ResourceLocation( eyeTex ) ); }
|
||||
|
||||
/** Sets the species default overlay texture. */
|
||||
private Builder vanillaOverlayTexture( String ovrTex ) { return overlayTexture( ovrTex == null ? null : new ResourceLocation( ovrTex ) ); }
|
||||
|
||||
|
||||
//--------------- Textures (Auto-selected) ----------------
|
||||
|
||||
/** Sets the species default base, glowing eyes, and overlay textures. */
|
||||
public Builder uniqueTexturesAll() { return uniqueBaseTexture().uniqueEyesTexture().uniqueOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base and glowing eyes textures. Removes all other textures. */
|
||||
public Builder uniqueTextureWithEyes() { return uniqueBaseTexture().uniqueEyesTexture().noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base and overlay textures. Removes all other textures. */
|
||||
public Builder uniqueTextureWithOverlay() { return uniqueBaseTexture().noEyesTexture().uniqueOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base and animation (overlay) textures. Removes all other textures. */
|
||||
public Builder uniqueTextureWithAnimation() { return uniqueBaseTexture().noEyesTexture().uniqueAnimationTexture(); }
|
||||
|
||||
/** Sets the species default base texture. Removes all other textures. */
|
||||
public Builder uniqueTextureBaseOnly() { return uniqueBaseTexture().noEyesTexture().noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base texture. */
|
||||
// Private because we always want to replace all textures when using a unique base
|
||||
private Builder uniqueBaseTexture() { return baseTexture( getBaseTexture() ); }
|
||||
|
||||
/** Sets the species default glowing eyes texture. */
|
||||
public Builder uniqueEyesTexture() { return eyesTexture( getEyesTexture() ); }
|
||||
|
||||
/** Sets the species default overlay texture. */
|
||||
public Builder uniqueOverlayTexture() { return overlayTexture( getOverlayTexture() ); }
|
||||
|
||||
/** Sets the species default animation texture (uses the overlay slot). */
|
||||
public Builder uniqueAnimationTexture() { return overlayTexture( getShootingTexture() ); }
|
||||
|
||||
/** @return The expected base texture for this builder. */
|
||||
private ResourceLocation getBaseTexture() { return toTexture( References.TEXTURE_BASE_SUFFIX ); }
|
||||
|
||||
/** @return The expected eyes texture for this builder. */
|
||||
private ResourceLocation getEyesTexture() { return toTexture( References.TEXTURE_EYES_SUFFIX ); }
|
||||
|
||||
/** @return The expected overlay texture for this builder. */
|
||||
private ResourceLocation getOverlayTexture() { return toTexture( References.TEXTURE_OVERLAY_SUFFIX ); }
|
||||
|
||||
/** @return The given strings converted to a texture resource location. */
|
||||
private ResourceLocation getShootingTexture() { return toTexture( References.TEXTURE_SHOOTING_SUFFIX ); }
|
||||
|
||||
/** @return The given strings converted to a texture resource location. */
|
||||
private ResourceLocation toTexture( String suffix ) {
|
||||
return SpecialMobs.resourceLoc( String.format( References.TEXTURE_FORMAT,
|
||||
ConfigUtil.camelCaseToLowerUnderscore( owningSpecies.family.name ),
|
||||
ConfigUtil.camelCaseToLowerUnderscore( owningSpecies.specialVariantName ), suffix ) );
|
||||
}
|
||||
|
||||
|
||||
//--------------- Textures (Misc/Internal) ----------------
|
||||
|
||||
/** Removes the species default glowing eyes texture. */
|
||||
public Builder noEyesTexture() { return eyesTexture( null ); }
|
||||
|
||||
/** Removes the species default overlay texture. */
|
||||
public Builder noOverlayTexture() { return overlayTexture( null ); }
|
||||
|
||||
/** Removes the species default animation texture (uses the overlay slot). */
|
||||
public Builder noAnimationTexture() { return noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base texture. */
|
||||
private Builder baseTexture( ResourceLocation tex ) {
|
||||
texture = tex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default glowing eyes texture. */
|
||||
private Builder eyesTexture( ResourceLocation eyeTex ) {
|
||||
eyesTexture = eyeTex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default overlay texture. */
|
||||
private Builder overlayTexture( ResourceLocation ovrTex ) {
|
||||
overlayTexture = ovrTex;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Creature Type Templates ----------------
|
||||
|
||||
/** Sets the standard species stats implied by being undead. */
|
||||
public Builder undead() { return effectImmune( Effects.REGENERATION, Effects.POISON ); }
|
||||
|
||||
/** Sets the standard species stats implied by being a spider. */
|
||||
public Builder spider() { return webImmune().effectImmune( Effects.POISON ); }
|
||||
|
||||
|
||||
//--------------- Special Mob Data ----------------
|
||||
|
||||
/** Sets the species experience value. */
|
||||
public Builder experience( int xp ) {
|
||||
experience = xp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds a flat amount to the species experience value. */
|
||||
public Builder addExperience( int xp ) { return experience( experience + xp ); }
|
||||
|
||||
/** Sets the species heal time. */
|
||||
public Builder regen( int time ) {
|
||||
healTime = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as fall damage immune. */
|
||||
public Builder fallImmune() { return fallDamage( 0.0 ); }
|
||||
|
||||
/** Sets the species fall damage multiplier. */
|
||||
public Builder fallDamage( double multiplier ) {
|
||||
fallDamageMultiplier = multiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as fire immune. */
|
||||
public Builder fireImmune() {
|
||||
entityTypeBuilder.fireImmune();
|
||||
isImmuneToFire = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as burning immune. */
|
||||
public Builder burnImmune() {
|
||||
isImmuneToBurning = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as drowning immune. */
|
||||
public Builder drownImmune() {
|
||||
canBreatheInWater = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as fluid-pushing immune. */
|
||||
public Builder fluidPushImmune() {
|
||||
ignoreWaterPush = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as damaged by water. */
|
||||
public Builder waterSensitive() {
|
||||
isDamagedByWater = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as leashable (can have a lead attached). */
|
||||
public Builder leashable() {
|
||||
allowLeashing = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as pressure plate immune. */
|
||||
public Builder pressurePlateImmune() {
|
||||
ignorePressurePlates = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the block hazards (damaging blocks) the species is immune to. */
|
||||
public Builder hazardImmune( Block... hazards ) {
|
||||
entityTypeBuilder.immuneTo( hazards );
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as cobweb immune. */
|
||||
public Builder webImmune() { return stickyBlockImmune( Blocks.COBWEB ); }
|
||||
|
||||
/** Sets the species as immune to a specific list of sticky blocks. */
|
||||
public Builder stickyBlockImmune( Block... blocks ) {
|
||||
immuneToStickyBlocks.addAll( Arrays.asList( blocks ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as immune to a specific list of effects. */
|
||||
public Builder effectImmune( Effect... effects ) {
|
||||
immuneToPotions.addAll( Arrays.asList( effects ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Ranged Attacks (Special Mob Data) ----------------
|
||||
|
||||
/** Sets the species ranged attack stats (for a bow user). */
|
||||
public Builder bowAttack( double damage, double spread, double walkSpeed, int cooldown, double range ) {
|
||||
return rangedDamage( damage ).rangedSpread( spread ).rangedWalkSpeed( walkSpeed ).rangedCooldown( cooldown ).rangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Sets the species ranged attack stats (for a fireball shooter). */
|
||||
public Builder fireballAttack( double spread, int charge, int cooldown, double range ) {
|
||||
return rangedSpread( spread ).rangedCooldown( charge ).rangedMaxCooldown( charge + cooldown ).rangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Sets the species ranged attack stats (for a spit shooter). */
|
||||
public Builder spitAttack( double damage, double spread, int cooldown, int extraCooldown, double range ) {
|
||||
return rangedDamage( damage ).rangedSpread( spread )
|
||||
.rangedCooldown( cooldown ).rangedMaxCooldown( cooldown + extraCooldown ).rangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Applies multipliers to the species ranged attack stats (for a spit shooter). */
|
||||
public Builder spitAttackMultiplied( double damage, double spread, float cooldown, double range ) {
|
||||
return multiplyRangedDamage( damage ).multiplyRangedSpread( spread )
|
||||
.multiplyRangedCooldown( cooldown ).multiplyRangedMaxCooldown( cooldown ).multiplyRangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Sets the species as unable to use ranged attacks (for any ranged user). */
|
||||
public Builder disableRangedAttack() { return rangedMaxRange( 0.0 ); }
|
||||
|
||||
/** Applies a flat modifier to the species ranged attack damage. */
|
||||
public Builder addToRangedDamage( double value ) { return rangedDamage( rangedAttackDamage + value ); }
|
||||
|
||||
/** Applies a multiplier to the species ranged attack damage. */
|
||||
public Builder multiplyRangedDamage( double value ) { return rangedDamage( rangedAttackDamage * value ); }
|
||||
|
||||
/** Sets the species ranged attack damage. */
|
||||
public Builder rangedDamage( double value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedAttackDamage < 0.0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedAttackDamage = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Applies a multiplier to the species ranged attack spread. */
|
||||
public Builder multiplyRangedSpread( double value ) { return rangedSpread( rangedAttackSpread * value ); }
|
||||
|
||||
/** Sets the species ranged attack spread. */
|
||||
public Builder rangedSpread( double value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedAttackSpread < 0.0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedAttackSpread = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Applies a multiplier to the species ranged attack walk speed. */
|
||||
public Builder multiplyRangedWalkSpeed( double value ) { return rangedWalkSpeed( rangedWalkSpeed * value ); }
|
||||
|
||||
/** Sets the species ranged attack walk speed. */
|
||||
public Builder rangedWalkSpeed( double value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedWalkSpeed < 0.0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedWalkSpeed = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Applies a multiplier to the species ranged attack cooldown. */
|
||||
public Builder multiplyRangedCooldown( float value ) { return rangedCooldown( Math.round( rangedAttackCooldown * value ) ); }
|
||||
|
||||
/** Sets the species ranged attack cooldown. */
|
||||
public Builder rangedCooldown( int value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedAttackCooldown < 0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedAttackCooldown = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Applies a multiplier to the species ranged attack max cooldown. */
|
||||
public Builder multiplyRangedMaxCooldown( float value ) { return rangedCooldown( Math.round( rangedAttackMaxCooldown * value ) ); }
|
||||
|
||||
/** Sets the species ranged attack max cooldown. */
|
||||
public Builder rangedMaxCooldown( int value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedAttackMaxCooldown < 0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedAttackMaxCooldown = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Applies a multiplier to the species ranged attack max range. */
|
||||
public Builder multiplyRangedMaxRange( double value ) { return rangedMaxRange( rangedAttackMaxRange * value ); }
|
||||
|
||||
/** Sets the species ranged attack max range. */
|
||||
public Builder rangedMaxRange( double value ) {
|
||||
if( owningSpecies.specialVariantName != null && rangedAttackMaxRange < 0.0 )
|
||||
throw new IllegalStateException( "Attempted to add inapplicable ranged attack stat!" );
|
||||
rangedAttackMaxRange = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//--------------- Attribute Changes ----------------
|
||||
|
||||
/** Adds a flat value to the base attribute. Not applicable for the movement speed attribute, use a multiplier instead. */
|
||||
public Builder addToAttribute( Attribute attribute, double value ) {
|
||||
if( attribute == Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Do not add flat movement speed!" );
|
||||
attributes.add( AttributeEntry.add( attribute, value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds a value multiplier to the base attribute. */
|
||||
public Builder multiplyAttribute( Attribute attribute, double value ) {
|
||||
attributes.add( AttributeEntry.mult( attribute, value ) );
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package fathertoast.specialmobs.common.bestiary;
|
||||
|
||||
import fathertoast.specialmobs.common.config.family.*;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.core.register.SMEntities;
|
||||
import fathertoast.specialmobs.common.core.register.SMItems;
|
||||
import fathertoast.specialmobs.common.util.AnnotationHelper;
|
||||
|
@ -17,6 +19,7 @@ import net.minecraftforge.fml.RegistryObject;
|
|||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Special mobs are broken up into distinct 'families', each of which correspond to a type of vanilla mob that can be
|
||||
|
@ -26,90 +29,90 @@ import java.util.*;
|
|||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
public class MobFamily<T extends LivingEntity> {
|
||||
public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
||||
/** List of all families, generated to make iteration possible. */
|
||||
private static final List<MobFamily<?>> FAMILY_LIST = new ArrayList<>();
|
||||
private static final List<MobFamily<?, ?>> FAMILY_LIST = new ArrayList<>();
|
||||
/** List of all species, generated to make iteration more convenient. */
|
||||
private static final List<Species<?>> SPECIES_LIST;
|
||||
|
||||
/** Maps each replaceable entity type to the family that replaces it. */
|
||||
private static final Map<EntityType<?>, MobFamily<?>> TYPE_TO_FAMILY_MAP;
|
||||
private static final Map<EntityType<?>, MobFamily<?, ?>> TYPE_TO_FAMILY_MAP;
|
||||
|
||||
// NOTE: When adding a new mob family, do not forget to also register its renderer in the client register!
|
||||
|
||||
public static final MobFamily<CreeperEntity> CREEPER = new MobFamily<>(
|
||||
public static final MobFamily<CreeperEntity, CreeperFamilyConfig> CREEPER = new MobFamily<>( CreeperFamilyConfig::new,
|
||||
"Creeper", "creepers", 0x0DA70B, new EntityType[] { EntityType.CREEPER },
|
||||
"Dark", "Death", "Dirt", "Doom", "Drowning", "Ender", "Fire", "Gravel", "Jumping", "Lightning",
|
||||
"Mini", /*"Scope",*/ "Skeleton", "Splitting"
|
||||
);
|
||||
|
||||
public static final MobFamily<ZombieEntity> ZOMBIE = new MobFamily<>(
|
||||
public static final MobFamily<ZombieEntity, FamilyConfig> ZOMBIE = new MobFamily<>( FamilyConfig::new,
|
||||
"Zombie", "zombies", 0x00AFAF, new EntityType[] { EntityType.ZOMBIE, EntityType.HUSK },
|
||||
"Brute", "Fire", /*"Fishing",*/ "Giant", "Hungry", "Husk", "MadScientist", "Plague"
|
||||
);
|
||||
// TODO Drowned family and zombie transform mechanic
|
||||
public static final MobFamily<ZombifiedPiglinEntity> ZOMBIFIED_PIGLIN = new MobFamily<>(//TODO figure out crossbows
|
||||
public static final MobFamily<ZombifiedPiglinEntity, FamilyConfig> ZOMBIFIED_PIGLIN = new MobFamily<>( FamilyConfig::new,
|
||||
"ZombifiedPiglin", "zombified piglins", 0xEA9393, new EntityType[] { EntityType.ZOMBIFIED_PIGLIN },
|
||||
"Brute", /*"Fishing",*/ "Giant", "Hungry", "Knight", "Plague", "Vampire"
|
||||
"Brute", /*"Fishing",*/ "Giant", "Hungry", "Knight", "Plague", "Vampire"//TODO figure out crossbows
|
||||
);
|
||||
|
||||
public static final MobFamily<AbstractSkeletonEntity> SKELETON = new MobFamily<>(
|
||||
public static final MobFamily<AbstractSkeletonEntity, SkeletonFamilyConfig> SKELETON = new MobFamily<>( SkeletonFamilyConfig::new,
|
||||
"Skeleton", "skeletons", 0xC1C1C1, new EntityType[] { EntityType.SKELETON, EntityType.STRAY },
|
||||
"Brute", "Fire", "Gatling", "Giant", "Knight", "Ninja", "Poison", "Sniper", "Spitfire", "Stray"
|
||||
);
|
||||
public static final MobFamily<AbstractSkeletonEntity> WITHER_SKELETON = new MobFamily<>(
|
||||
public static final MobFamily<AbstractSkeletonEntity, SkeletonFamilyConfig> WITHER_SKELETON = new MobFamily<>( SkeletonFamilyConfig::new,
|
||||
"WitherSkeleton", "wither skeletons", 0x141414, new EntityType[] { EntityType.WITHER_SKELETON },
|
||||
"Brute", "Gatling", "Giant", "Knight", "Ninja", "Sniper", "Spitfire"
|
||||
);
|
||||
|
||||
public static final MobFamily<SlimeEntity> SLIME = new MobFamily<>(
|
||||
public static final MobFamily<SlimeEntity, SlimeFamilyConfig> SLIME = new MobFamily<>( SlimeFamilyConfig::new,
|
||||
"Slime", "slimes", 0x51A03E, new EntityType[] { EntityType.SLIME },
|
||||
"Blackberry", "Blueberry", "Caramel", "Grape", "Lemon", "Strawberry", "Watermelon"
|
||||
);
|
||||
public static final MobFamily<MagmaCubeEntity> MAGMA_CUBE = new MobFamily<>(
|
||||
public static final MobFamily<MagmaCubeEntity, FamilyConfig> MAGMA_CUBE = new MobFamily<>( FamilyConfig::new,
|
||||
"MagmaCube", "magma cubes", 0x340000, new EntityType[] { EntityType.MAGMA_CUBE },
|
||||
"Bouncing", "Hardened", "Sticky", "Volatile"
|
||||
);
|
||||
|
||||
public static final MobFamily<SpiderEntity> SPIDER = new MobFamily<>(
|
||||
public static final MobFamily<SpiderEntity, FamilyConfig> SPIDER = new MobFamily<>( FamilyConfig::new,
|
||||
"Spider", "spiders", 0x342D27, new EntityType[] { EntityType.SPIDER },
|
||||
"Baby", "Desert", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", /*"Water",*/ "Web", "Witch"
|
||||
);
|
||||
public static final MobFamily<CaveSpiderEntity> CAVE_SPIDER = new MobFamily<>(
|
||||
public static final MobFamily<CaveSpiderEntity, FamilyConfig> CAVE_SPIDER = new MobFamily<>( FamilyConfig::new,
|
||||
"CaveSpider", "cave spiders", 0x0C424E, new EntityType[] { EntityType.CAVE_SPIDER },
|
||||
"Baby", "Flying", "Mother", /*"Water",*/ "Web", "Witch"
|
||||
);
|
||||
|
||||
public static final MobFamily<SilverfishEntity> SILVERFISH = new MobFamily<>(
|
||||
public static final MobFamily<SilverfishEntity, SilverfishFamilyConfig> SILVERFISH = new MobFamily<>( SilverfishFamilyConfig::new,
|
||||
"Silverfish", "silverfish", 0x6E6E6E, new EntityType[] { EntityType.SILVERFISH },
|
||||
"Blinding", /*"Fishing",*/ "Flying", "Poison", /*"Puffer",*/ "Tough"
|
||||
);
|
||||
|
||||
public static final MobFamily<EndermanEntity> ENDERMAN = new MobFamily<>(
|
||||
public static final MobFamily<EndermanEntity, FamilyConfig> ENDERMAN = new MobFamily<>( FamilyConfig::new,
|
||||
"Enderman", "endermen", 0x161616, new EntityType[] { EntityType.ENDERMAN },
|
||||
"Blinding", "Icy", "Lightning", "Mini", "Mirage", "Thief"
|
||||
);
|
||||
|
||||
public static final MobFamily<WitchEntity> WITCH = new MobFamily<>(
|
||||
public static final MobFamily<WitchEntity, WitchFamilyConfig> WITCH = new MobFamily<>( WitchFamilyConfig::new,
|
||||
"Witch", "witches", 0x340000, new EntityType[] { EntityType.WITCH },
|
||||
"Domination", "Shadows", "Undead", "Wilds", "Wind"
|
||||
);
|
||||
|
||||
public static final MobFamily<GhastEntity> GHAST = new MobFamily<>(
|
||||
public static final MobFamily<GhastEntity, GhastFamilyConfig> GHAST = new MobFamily<>( GhastFamilyConfig::new,
|
||||
"Ghast", "ghasts", 0xF9F9F9, new EntityType[] { EntityType.GHAST },
|
||||
"Baby", "Fighter", "King", "Queen", "Unholy", "CorporealShift"
|
||||
);
|
||||
|
||||
public static final MobFamily<BlazeEntity> BLAZE = new MobFamily<>(
|
||||
public static final MobFamily<BlazeEntity, FamilyConfig> BLAZE = new MobFamily<>( FamilyConfig::new,
|
||||
"Blaze", "blazes", 0xF6B201, new EntityType[] { EntityType.BLAZE },
|
||||
"Cinder", "Conflagration", "Ember", "Hellfire", "Inferno", "Jolt", "Wildfire"
|
||||
);
|
||||
|
||||
static {
|
||||
final HashMap<EntityType<?>, MobFamily<?>> classToFamilyMap = new HashMap<>();
|
||||
final HashMap<EntityType<?>, MobFamily<?, ?>> classToFamilyMap = new HashMap<>();
|
||||
final ArrayList<Species<?>> allSpecies = new ArrayList<>();
|
||||
|
||||
for( MobFamily<?> family : FAMILY_LIST ) {
|
||||
for( MobFamily<?, ?> family : FAMILY_LIST ) {
|
||||
for( EntityType<?> replaceable : family.replaceableTypes )
|
||||
classToFamilyMap.put( replaceable, family );
|
||||
|
||||
|
@ -126,23 +129,23 @@ public class MobFamily<T extends LivingEntity> {
|
|||
public static void initBestiary() { }
|
||||
|
||||
/** @return A list of all families. */
|
||||
public static List<MobFamily<?>> getAll() { return Collections.unmodifiableList( FAMILY_LIST ); }
|
||||
public static List<MobFamily<?, ?>> getAll() { return Collections.unmodifiableList( FAMILY_LIST ); }
|
||||
|
||||
/** @return A list of all species. */
|
||||
public static List<Species<?>> getAllSpecies() { return SPECIES_LIST; }
|
||||
|
||||
/** @return The family of mobs that can replace the passed entity; returns null if the entity is not replaceable. */
|
||||
@Nullable
|
||||
public static MobFamily<?> getReplacementFamily( LivingEntity entity ) {
|
||||
public static MobFamily<?, ?> getReplacementFamily( LivingEntity entity ) {
|
||||
return TYPE_TO_FAMILY_MAP.get( entity.getType() );
|
||||
}
|
||||
|
||||
/** The technical name that refers to this family. Note that this is UpperCamelCase, but is often used in lowercase. */
|
||||
public final String name;
|
||||
/** The name used to refer to this family in unlocalized situations; e.g. config comments. */
|
||||
/** The plural name used to refer to this family in unlocalized situations; e.g. config comments. */
|
||||
public final String configName;
|
||||
|
||||
/** The base egg color for species in this family. Species' eggs differ visually only by spot color. */
|
||||
/** The base color for spawn eggs of species in this family. Species' eggs differ visually only by spot color. */
|
||||
public final int eggBaseColor;
|
||||
|
||||
/** List of replaceable entity types. The vanilla replacement's entity type is based on the first entry in this array. */
|
||||
|
@ -156,25 +159,31 @@ public class MobFamily<T extends LivingEntity> {
|
|||
/** Array of all special variant species in this family. In practice, these are the true "special mobs". */
|
||||
public final Species<? extends T>[] variants;
|
||||
|
||||
//public Config.FamilyConfig config;
|
||||
/** This family's config. */
|
||||
public final V config;
|
||||
|
||||
private MobFamily( String familyName, String familyKey, int eggColor, EntityType<?>[] replaceable,
|
||||
private MobFamily( Function<MobFamily<?, ?>, V> configSupplier,
|
||||
String familyName, String readableName, int eggColor, EntityType<?>[] replaceable,
|
||||
String... variantNames ) {
|
||||
name = familyName;
|
||||
configName = familyKey;
|
||||
configName = readableName.toLowerCase( Locale.ROOT );
|
||||
eggBaseColor = eggColor;
|
||||
replaceableTypes = replaceable;
|
||||
if( replaceable.length < 1 )
|
||||
throw new IllegalArgumentException( familyName + " family must have at least one replaceable type!" );
|
||||
|
||||
final String packageRoot = References.ENTITY_PACKAGE + name.toLowerCase() + ".";
|
||||
final String packageRoot = References.ENTITY_PACKAGE + name.toLowerCase();
|
||||
vanillaReplacement = new Species<>( this, packageRoot, null );
|
||||
|
||||
//noinspection unchecked
|
||||
variants = new Species[variantNames.length];
|
||||
for( int i = 0; i < variants.length; i++ ) {
|
||||
variants[i] = new Species<>( this, packageRoot, variantNames[i] );
|
||||
}
|
||||
|
||||
config = configSupplier.apply( this );
|
||||
config.SPEC.initialize();
|
||||
|
||||
// We register here because otherwise there's no way to find all families
|
||||
FAMILY_LIST.add( this );
|
||||
}
|
||||
|
@ -223,7 +232,7 @@ public class MobFamily<T extends LivingEntity> {
|
|||
@MethodsReturnNonnullByDefault
|
||||
public static class Species<T extends LivingEntity> {
|
||||
/** The special mob family this species belongs to. */
|
||||
public final MobFamily<? super T> family;
|
||||
public final MobFamily<? super T, ?> family;
|
||||
/** The name of this special variant; or null for vanilla replacement species. */
|
||||
public final String specialVariantName;
|
||||
/** The technical name that refers to this species. Note that this is UpperCamelCase, but is often used in lowercase. */
|
||||
|
@ -231,7 +240,7 @@ public class MobFamily<T extends LivingEntity> {
|
|||
|
||||
/** The entity class for this species. */
|
||||
public final Class<T> entityClass;
|
||||
/** The bestiary info describing this species */
|
||||
/** The bestiary info describing this species. */
|
||||
public final BestiaryInfo bestiaryInfo;
|
||||
|
||||
/** This species's entity type, wrapped in its registry object. */
|
||||
|
@ -239,8 +248,11 @@ public class MobFamily<T extends LivingEntity> {
|
|||
/** This species's spawn egg item, wrapped in its registry object. */
|
||||
public final RegistryObject<ForgeSpawnEggItem> spawnEgg;
|
||||
|
||||
/** This species's config. */
|
||||
public final SpeciesConfig config;
|
||||
|
||||
/** Constructs a new mob species. For vanilla replacements, the variant name is null. */
|
||||
private Species( MobFamily<? super T> parentFamily, String packageRoot, @Nullable String variantName ) {
|
||||
private Species( MobFamily<? super T, ?> parentFamily, String packageRoot, @Nullable String variantName ) {
|
||||
final boolean vanillaReplacement = variantName == null;
|
||||
|
||||
family = parentFamily;
|
||||
|
@ -253,14 +265,19 @@ public class MobFamily<T extends LivingEntity> {
|
|||
|
||||
// Below require variant class to be defined
|
||||
final EntityType.Builder<T> entityTypeBuilder = makeEntityTypeBuilder( parentFamily.replaceableTypes[0] );
|
||||
bestiaryInfo = AnnotationHelper.getBestiaryInfo( this, entityTypeBuilder );
|
||||
bestiaryInfo = AnnotationHelper.getBestiaryInfo( this, BestiaryInfo.of( this, entityTypeBuilder ) ).build();
|
||||
|
||||
// Initialize deferred registry objects
|
||||
entityType = SMEntities.register( name.toLowerCase( Locale.ROOT ), entityTypeBuilder );
|
||||
spawnEgg = SMItems.registerSpawnEgg( entityType, parentFamily.eggBaseColor, bestiaryInfo.eggSpotsColor );
|
||||
|
||||
// Config uses bestiary info for default values
|
||||
config = AnnotationHelper.createConfig( this );
|
||||
config.SPEC.initialize();
|
||||
|
||||
// Register this species with the entity class
|
||||
AnnotationHelper.injectSpeciesReference( this );
|
||||
AnnotationHelper.verifySpeciesSupplier( this );
|
||||
}
|
||||
|
||||
/** Finds the entity class based on a standard format. */
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package fathertoast.specialmobs.common.bestiary;
|
||||
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -14,50 +16,77 @@ import java.lang.annotation.Target;
|
|||
*/
|
||||
@Target( ElementType.TYPE )
|
||||
public @interface SpecialMob {
|
||||
|
||||
/**
|
||||
* REQUIRED. This is injected with a reference to the species during registration so you may access it later, as needed.
|
||||
* <p>
|
||||
* The annotated field must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static MobFamily.Species<T> FIELD_NAME;
|
||||
* {@code public static MobFamily.Species<T> FIELD_NAME;}
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.FIELD )
|
||||
@interface SpeciesReference { }
|
||||
|
||||
/**
|
||||
* REQUIRED. This is called during registration to collect static properties of the mob needed for the bestiary
|
||||
* and for building the species's entity type.
|
||||
* This is not 'overridable' because all species must have unique info in the bestiary.
|
||||
* REQUIRED. This is used to enforce overriding {@link ISpecialMob#getSpecies()} in every species entity class.
|
||||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static BestiaryInfo METHOD_NAME( EntityType.Builder<LivingEntity> entityType )
|
||||
* {@code public MobFamily.Species<? extends T> getSpecies();}
|
||||
* <p>
|
||||
* The returned bestiary info will be used to describe the mob species.
|
||||
* The builder passed in is a copy of the vanilla 'base' entity type. Common uses of the entity type builder are
|
||||
* modifying entity size and fire/hazard immunities.
|
||||
* The returned species should be the field annotated with {@link SpecialMob.SpeciesReference}.
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.METHOD )
|
||||
@interface SpeciesSupplier { }
|
||||
|
||||
/**
|
||||
* REQUIRED. This is called during registration to collect static properties of the mob needed for the bestiary
|
||||
* and for building the species's entity type.
|
||||
* This is not 'overridable' because all species must have unique info in the bestiary, however some info in the
|
||||
* builder is automatically inherited.
|
||||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* {@code public static void METHOD_NAME( BestiaryInfo.Builder bestiaryInfo )}
|
||||
* <p>
|
||||
* The provided bestiary info builder is initialized with as much data from the parent entity as possible.
|
||||
* The only builder method that absolutely must be called is #color( int ). This will likely later expand to desc.
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.METHOD )
|
||||
@interface BestiaryInfoSupplier { }
|
||||
|
||||
/**
|
||||
* OVERRIDABLE. This is called during registration to build the base attributes for the species.
|
||||
* 'Overridable' static methods inherit from their superclass if not defined in a subclass, but must be defined somewhere.
|
||||
* This is 'overridable' because not all species need to have different attributes from their parent vanilla mob.
|
||||
* OPTIONAL-OVERRIDABLE. This is called during registration to generate the species config.
|
||||
* 'Overridable' static methods inherit from their superclass if not defined in a subclass.
|
||||
* This is 'overridable' because not all species (or even families) require unique config categories.
|
||||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static AttributeModifierMap.MutableAttribute METHOD_NAME()
|
||||
* {@code public static SpeciesConfig METHOD_NAME( MobFamily.Species<?> species )}
|
||||
* <p>
|
||||
* The returned config will be loaded immediately after the call and a reference will be stored in the species.
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.METHOD )
|
||||
@interface ConfigSupplier { }
|
||||
|
||||
/**
|
||||
* OVERRIDABLE. This is called during registration to build the base attributes for the species.
|
||||
* 'Overridable' static methods inherit from their superclass if not defined in a subclass, but must be defined somewhere.
|
||||
* This is 'overridable' because a few species have a different parent vanilla mob from the rest of their family.
|
||||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* {@code public static AttributeModifierMap.MutableAttribute METHOD_NAME()}
|
||||
* <p>
|
||||
* The returned attribute modifier map builder will be 'built' immediately after the call and registered to be
|
||||
* applied to all entity class instances of the mob species.
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.METHOD )
|
||||
@interface AttributeCreator { }
|
||||
@interface AttributeSupplier { }
|
||||
|
||||
/**
|
||||
* REQUIRED. This is called during data generation to build the mod's default lang files.
|
||||
|
@ -65,7 +94,7 @@ public @interface SpecialMob {
|
|||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static String[] METHOD_NAME( String langKey )
|
||||
* {@code public static String[] METHOD_NAME( String langKey )}
|
||||
* <p>
|
||||
* The returned string array should be created by References#translations using the given lang key as the first
|
||||
* argument. Always be sure that any non-ASCII characters used are properly handled by the translations method.
|
||||
|
@ -83,7 +112,7 @@ public @interface SpecialMob {
|
|||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static void METHOD_NAME( LootTableBuilder loot )
|
||||
* {@code public static void METHOD_NAME( LootTableBuilder loot )}
|
||||
* <p>
|
||||
* The builder passed in is a new empty instance and will be 'built' immediately after the call.
|
||||
*/
|
||||
|
@ -98,7 +127,7 @@ public @interface SpecialMob {
|
|||
* <p>
|
||||
* The annotated method must have a signature that follows the pattern:
|
||||
* <p>
|
||||
* public static EntityType.IFactory<T> METHOD_NAME()
|
||||
* {@code public static EntityType.IFactory<T> METHOD_NAME()}
|
||||
*/
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( ElementType.METHOD )
|
||||
|
|
|
@ -35,7 +35,7 @@ public class Config {
|
|||
/** The spec used by this config that defines the file's format. */
|
||||
public final ToastConfigSpec SPEC;
|
||||
|
||||
AbstractConfig( File dir, String fileName, String... fileDescription ) {
|
||||
public AbstractConfig( File dir, String fileName, String... fileDescription ) {
|
||||
AbstractConfigField.loadingCategory = "";
|
||||
SPEC = new ToastConfigSpec( dir, fileName );
|
||||
SPEC.header( TomlHelper.newComment( fileDescription ) );
|
||||
|
@ -50,17 +50,10 @@ public class Config {
|
|||
/** The spec used by this config that defines the file's format. */
|
||||
protected final ToastConfigSpec SPEC;
|
||||
|
||||
AbstractCategory( ToastConfigSpec parent, String name, String... categoryDescription ) {
|
||||
public AbstractCategory( ToastConfigSpec parent, String name, String... categoryDescription ) {
|
||||
AbstractConfigField.loadingCategory = name + ".";
|
||||
SPEC = parent;
|
||||
SPEC.category( name, TomlHelper.newComment( categoryDescription ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** The plus or minus symbol (+/-). */
|
||||
public static final String PLUS_OR_MINUS = "\u00b1";
|
||||
/** The less than or equal to symbol (<=). */
|
||||
public static final String LESS_OR_EQUAL = "\u2264";
|
||||
/** The greater than or equal to symbol (>=). */
|
||||
public static final String GREATER_OR_EQUAL = "\u2265";
|
||||
}
|
|
@ -2,6 +2,7 @@ package fathertoast.specialmobs.common.config;
|
|||
|
||||
import fathertoast.specialmobs.common.config.field.*;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -12,58 +13,61 @@ public class MainConfig extends Config.AbstractConfig {
|
|||
/** Builds the config spec that should be used for this config. */
|
||||
MainConfig( File dir, String fileName ) {
|
||||
super( dir, fileName,
|
||||
"This config contains options that apply to the mod as a whole, including some master disable",
|
||||
"toggles for convenience."
|
||||
);
|
||||
"This config contains options that apply to the mod as a whole, including some master settings",
|
||||
"toggles for convenience.",
|
||||
"",
|
||||
"Terminology used in Special Mobs configs:",
|
||||
" * Mob - An entity that is 'alive', short for \"Mobile\" or MobEntity.",
|
||||
" * Family - The group of mobs based on (but not including) a particular vanilla mob; e.g., Creepers.",
|
||||
" * Species - A specific type of mob within a family; e.g., Fire Creepers or vanilla-replacement Creepers.",
|
||||
" * Vanilla Replacement - The one species within a family that is intended to be a replica of the base vanilla mob.",
|
||||
" * Special Variant - Any species that is not the family's vanilla replacement. Includes species that are",
|
||||
" replicas of 'vanilla special variants'; i.e. Husks and Strays.",
|
||||
" * Mob Replacer - The tool that watches vanilla mob spawns and cancels them to spawn this mod's entities." );
|
||||
|
||||
GENERAL = new General( SPEC );
|
||||
}
|
||||
|
||||
public static class General extends Config.AbstractCategory {
|
||||
|
||||
public final IntField updateTime;
|
||||
public final BooleanField enableMobReplacement;
|
||||
|
||||
public final InjectionWrapperField<BooleanField> defaultGameRuleNoRegen;
|
||||
public final BooleanField masterVanillaReplacement;
|
||||
public final DoubleField masterRandomScaling;
|
||||
|
||||
public final BooleanField foodExtraTooltipInfo;
|
||||
|
||||
public final BooleanField disableAbsorptionFeatures;
|
||||
public final BooleanField disableHealthFeatures;
|
||||
//public final BooleanField disableHungerFeatures; // NOTE: If/when hunger features are added, also move food configs from health
|
||||
public final BooleanField enableNausea;
|
||||
public final BooleanField fancyFishingMobs;
|
||||
|
||||
General( ToastConfigSpec parent ) {
|
||||
super( parent, "general",
|
||||
"Options for customizing the mod as a whole." );
|
||||
"Options that apply to the Special Mobs mod as a whole.",
|
||||
"Also includes several 'master toggles' for convenience." );
|
||||
|
||||
updateTime = SPEC.define( new IntField( "update_time", 5, IntField.Range.POSITIVE,
|
||||
"The number of ticks between this mod's logic/recovery updates (20 ticks = 1 second)." ) );
|
||||
enableMobReplacement = SPEC.define( new BooleanField( "enable_mob_replacer", true,
|
||||
"Whether the Mob Replacer is enabled. This 'hijacks' vanilla mob spawns to use as its own.",
|
||||
"The Mob Replacer is the traditional spawn method for Special Mobs which allows everything that spawns",
|
||||
"valid vanilla mobs (e.g. dungeon spawners) to spawn this mod's mobs based on your configs instead." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
defaultGameRuleNoRegen = SPEC.define( new InjectionWrapperField<>(
|
||||
new BooleanField( "default_regen_game_rule_disabled", true,
|
||||
"When set to true, this mod will alter the vanilla regeneration game rule \"naturalRegeneration\" to",
|
||||
"be \"false\" by default when creating new worlds.",
|
||||
"Regardless of this config setting, you can still create a world with vanilla health regen ON or OFF",
|
||||
"by using the Game Rules button on the new world options screen or by using commands in-game." ),
|
||||
( wrapped ) -> {
|
||||
// Note, we are assuming the default is always true without this mod (ie, no other mod changes the default)
|
||||
//GameRules.GAME_RULE_TYPES.put( GameRules.RULE_NATURAL_REGENERATION,
|
||||
// GameRules.BooleanValue.create( !wrapped.get() ) );
|
||||
} ) );
|
||||
masterVanillaReplacement = SPEC.define( new BooleanField( "master_vanilla_replacement", true,
|
||||
"Whether the mod uses Special Mobs entities in place of vanilla entities for non-special species.",
|
||||
"This allows your config options to apply to non-special species and allows them to benefit from",
|
||||
"Special Mob Data and any improvements made to the entity (for example, zombies can use bows & shields).",
|
||||
"If false, vanilla replacements are disabled for all families; if true, it is determined by the family's config." ) );
|
||||
masterRandomScaling = SPEC.define( new DoubleField( "master_random_scaling", 0.07, DoubleField.Range.PERCENT,
|
||||
"When greater than 0, mobs will have a random render scale applied. This is a visual effect only.",
|
||||
"For example, with a value of 0.07, mob scale will vary " + ConfigUtil.PLUS_OR_MINUS + "7% of normal size.",
|
||||
"By default, this applies to all mobs in the mod; but family and species configs can override it." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
foodExtraTooltipInfo = SPEC.define( new BooleanField( "food.extra_tooltip_info", true,
|
||||
"Set to true to display nutritional value on the tooltips of food items.",
|
||||
"Lists hunger and saturation that can be restored from eating. (See health config for healing display.)" ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
disableAbsorptionFeatures = SPEC.define( new BooleanField( "disable_absorption_features", false,
|
||||
"If set to 'true', disables all features in this mod related to absorption (yellow hearts)." ) );
|
||||
disableHealthFeatures = SPEC.define( new BooleanField( "disable_health_features", false,
|
||||
"If set to 'true', disables all features in this mod related to health (red hearts)." ) );
|
||||
enableNausea = SPEC.define( new BooleanField( "enable_nausea_effects", true,
|
||||
"Set to false to prevent any of this mod's mobs from applying nausea (aka confusion).",
|
||||
"Use this if the screen warping from nausea hurts your face or makes you sick." ) );
|
||||
fancyFishingMobs = SPEC.define( new BooleanField( "fancy_fishing_mobs", true,
|
||||
"Overrides the default fishing rod item animation so that it is compatible with fishing mobs from this mod.",
|
||||
"Set to false if it causes problems with another mod. Fishing mobs will instead render a stick while casting." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for creepers.
|
||||
*/
|
||||
public class CreeperFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Creepers CREEPERS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public CreeperFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
CREEPERS = new Creepers( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Creepers extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField familyStormChargeChance;
|
||||
|
||||
public final DoubleField superchargeChance;
|
||||
|
||||
Creepers( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
familyStormChargeChance = SPEC.define( new DoubleField( "family_storm_charge_chance", 0.01, DoubleField.Range.PERCENT,
|
||||
"Chance for " + family.configName + " to spawn charged during thunderstorms.",
|
||||
"By default, this applies to all " + family.configName + "; but species configs can override it." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
superchargeChance = SPEC.define( new DoubleField( "supercharge_chance", 0.1, DoubleField.Range.PERCENT,
|
||||
"Chance for " + family.configName + " to become supercharged when charged in any way." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the base config for mob families. This may be extended to add categories specific to the family, but all
|
||||
* options that are used by all families should be defined in this class.
|
||||
*/
|
||||
public class FamilyConfig extends Config.AbstractConfig {
|
||||
|
||||
public static File dir( MobFamily<?, ?> family ) { return new File( Config.CONFIG_DIR, ConfigUtil.noSpaces( family.configName ) ); }
|
||||
|
||||
protected static String fileName( MobFamily<?, ?> family ) { return "_family_of_" + ConfigUtil.noSpaces( family.configName ); }
|
||||
|
||||
/** Category containing all options applicable to mob families as a whole; i.e. not specific to any particular family. */
|
||||
public final General GENERAL;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public FamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( dir( family ), fileName( family ),
|
||||
"This config contains options that apply to the family of " + family.configName + " as a whole;",
|
||||
"that is, the vanilla replacement and all special variants." );
|
||||
|
||||
GENERAL = new General( SPEC, family );
|
||||
}
|
||||
|
||||
public static class General extends Config.AbstractCategory {
|
||||
|
||||
public final BooleanField vanillaReplacement;
|
||||
|
||||
public final DoubleField familyRandomScaling;
|
||||
|
||||
public final DoubleField specialVariantChance;
|
||||
|
||||
public final IntField[] specialVariantWeights;
|
||||
|
||||
General( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, "general",
|
||||
"Options standard to all mob families (that is, not specific to any particular mob family)." );
|
||||
|
||||
vanillaReplacement = SPEC.define( new BooleanField( "vanilla_replacement", true,
|
||||
"Whether this mob family replaces vanilla " + family.configName + " with its vanilla replacement species.",
|
||||
"The \"master_vanilla_replacement\" setting in the mod's main config must also be true for this to work." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
familyRandomScaling = SPEC.define( new DoubleField( "family_random_scaling", -1.0, DoubleField.Range.SIGNED_PERCENT,
|
||||
"When greater than 0, " + family.configName + " will have a random render scale applied. This is a visual effect only.",
|
||||
"If this is set to a non-negative value, it overrides the value set for \"master_random_scaling\", though",
|
||||
"species configs can override this value." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
specialVariantChance = SPEC.define( new DoubleField( "special_variant_chance", 0.25, DoubleField.Range.PERCENT,
|
||||
"The chance for " + family.configName + " to spawn as special variants." ) );
|
||||
// TODO special variant chance exceptions
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
List<String> comment;
|
||||
|
||||
// TODO consider wrapping this all up into an 'environment sensitive weighted list' config object? seems handy
|
||||
comment = TomlHelper.newComment(
|
||||
"The weight of each " + ConfigUtil.camelCaseToLowerSpace( family.name ) + " species to be chosen as the replacement when",
|
||||
family.configName + " spawn as special variants. Higher weight is more common." );
|
||||
comment.add( TomlHelper.multiFieldInfo( IntField.Range.NON_NEGATIVE ) );
|
||||
SPEC.comment( comment );
|
||||
specialVariantWeights = new IntField[family.variants.length];
|
||||
for( int i = 0; i < specialVariantWeights.length; i++ ) {
|
||||
specialVariantWeights[i] = SPEC.define( new IntField(
|
||||
"weight." + ConfigUtil.camelCaseToLowerUnderscore( family.variants[i].specialVariantName ),
|
||||
family.variants[i].bestiaryInfo.defaultWeight.value, IntField.Range.NON_NEGATIVE, (String[]) null ) );
|
||||
}
|
||||
// TODO special variant weights exceptions
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for ghasts.
|
||||
*/
|
||||
public class GhastFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Ghasts GHASTS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public GhastFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
GHASTS = new Ghasts( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Ghasts extends Config.AbstractCategory {
|
||||
|
||||
public final BooleanField allowVerticalTargeting;
|
||||
|
||||
Ghasts( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
allowVerticalTargeting = SPEC.define( new BooleanField( "allow_vertical_targeting", true,
|
||||
"If true, " + family.configName + " will be allowed to target any visible player in their follow range.",
|
||||
"As of MC 1.8, vanilla ghasts can only start targeting players nearly completely horizontal from them." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for silverfish.
|
||||
*/
|
||||
public class SilverfishFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Silverfish SILVERFISH;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SilverfishFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
SILVERFISH = new Silverfish( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Silverfish extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField familyAggressiveChance;
|
||||
|
||||
Silverfish( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
familyAggressiveChance = SPEC.define( new DoubleField( "family_aggressive_chance", 0.05, DoubleField.Range.PERCENT,
|
||||
"Chance for " + family.configName + " to spawn already calling for reinforcements.",
|
||||
"By default, this applies to all " + family.configName + "; but species configs can override it." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for skeletons and wither skeletons.
|
||||
*/
|
||||
public class SkeletonFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Skeletons SKELETONS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SkeletonFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
SKELETONS = new Skeletons( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Skeletons extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField babyChance;
|
||||
|
||||
Skeletons( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
babyChance = SPEC.define( new DoubleField( "baby_chance", 0.05, DoubleField.Range.PERCENT,
|
||||
"Chance for valid " + family.configName + " to spawn as babies. Baby mobs are about half-sized,",
|
||||
"move 50% faster, drop 150% more experience, and are 50% cuter." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for slimes (NOT magma cubes).
|
||||
*/
|
||||
public class SlimeFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Slimes SLIMES;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SlimeFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
SLIMES = new Slimes( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Slimes extends Config.AbstractCategory {
|
||||
|
||||
public final BooleanField tinySlimesDealDamage;
|
||||
|
||||
Slimes( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
tinySlimesDealDamage = SPEC.define( new BooleanField( "tiny_slimes_deal_damage", true,
|
||||
"If true, the smallest size " + family.configName + " will be allowed to deal damage (unlike vanilla)." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the family config for witches.
|
||||
*/
|
||||
public class WitchFamilyConfig extends FamilyConfig {
|
||||
|
||||
public final Witches WITCHES;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public WitchFamilyConfig( MobFamily<?, ?> family ) {
|
||||
super( family );
|
||||
|
||||
WITCHES = new Witches( SPEC, family );
|
||||
}
|
||||
|
||||
public static class Witches extends Config.AbstractCategory {
|
||||
|
||||
public final BooleanField useSplashSwiftness;
|
||||
|
||||
Witches( ToastConfigSpec parent, MobFamily<?, ?> family ) {
|
||||
super( parent, ConfigUtil.noSpaces( family.configName ),
|
||||
"Options specific to the family of " + family.configName + "." );
|
||||
|
||||
useSplashSwiftness = SPEC.define( new BooleanField( "use_splash_swiftness", true,
|
||||
"If true, " + family.configName + " will use splash potions of swiftness when trying to keep up,",
|
||||
"rather than drinking a swiftness potion. Helps them keep up just a little better than vanilla." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.config.util.AttributeEntry;
|
||||
import fathertoast.specialmobs.common.config.util.AttributeList;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a config field with an entity list value.
|
||||
*/
|
||||
public class AttributeListField extends GenericField<AttributeList> {
|
||||
|
||||
/** Provides a detailed description of how to use attribute lists. Recommended to put at the top of any file using attribute lists. */
|
||||
public static List<String> verboseDescription() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Attribute List fields: General format = [ \"namespace:attribute_name operation value\", ... ]" );
|
||||
comment.add( " Attribute lists are arrays of base attribute changes. Attributes are defined by their key in the attribute registry," );
|
||||
comment.add( " usually following the pattern 'namespace:attribute_name'. The operations that can be performed are +, -, and *. The + and -" );
|
||||
comment.add( " operators change the attribute by a flat value by addition/subtraction. The * operator changes the attribute by multiplication." );
|
||||
comment.add( " Each entry in the attribute list is applied in the exact order listed." );
|
||||
comment.add( " As an example, the entry \"minecraft:generic.max_health + 10.0\" will increase a mob's max health by 10. By convention, never" );
|
||||
comment.add( " use the + or - operators for movement speed (minecraft:generic.movement_speed)." );
|
||||
return comment;
|
||||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public AttributeListField( String key, AttributeList defaultValue, String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
/** Applies all attribute changes in this list to the entity attribute builder. */
|
||||
public void apply( AttributeModifierMap.MutableAttribute builder ) { get().apply( builder ); }
|
||||
|
||||
/** Applies all attribute changes in this list to the entity. */
|
||||
public void apply( LivingEntity entity ) { get().apply( entity ); }
|
||||
|
||||
/** Adds info about the field type, format, and bounds to the end of a field's description. */
|
||||
public void appendFieldInfo( List<String> comment ) {
|
||||
comment.add( TomlHelper.fieldInfoFormat( "Attribute List", valueDefault,
|
||||
"[ \"namespace:attribute_name operation value\", ... ]" ) );
|
||||
comment.add( " Range for Values: " + TomlHelper.fieldRange( DoubleField.Range.ANY.MIN, DoubleField.Range.ANY.MAX ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this field's value from the given raw toml value. If anything goes wrong, correct it at the lowest level possible.
|
||||
* <p>
|
||||
* For example, a missing value should be set to the default, while an out-of-range value should be adjusted to the
|
||||
* nearest in-range value
|
||||
*/
|
||||
@Override
|
||||
public void load( @Nullable Object raw ) {
|
||||
if( raw == null ) {
|
||||
value = valueDefault;
|
||||
return;
|
||||
}
|
||||
List<String> list = TomlHelper.parseStringList( raw );
|
||||
List<AttributeEntry> entryList = new ArrayList<>();
|
||||
for( String line : list ) {
|
||||
AttributeEntry entry = parseEntry( line );
|
||||
if( entry != null ) {
|
||||
entryList.add( entry );
|
||||
}
|
||||
}
|
||||
value = new AttributeList( entryList );
|
||||
}
|
||||
|
||||
/** Parses a single entry line and returns a valid result if possible, or null if the entry is completely invalid. */
|
||||
@Nullable
|
||||
private AttributeEntry parseEntry( final String line ) {
|
||||
// Parse the attribute-operation-value array
|
||||
final String[] args = line.split( " ", 4 );
|
||||
if( args.length > 3 ) {
|
||||
SpecialMobs.LOG.warn( "Entry has for {} \"{}\" is too long! Deleting excess. Invalid entry: {}",
|
||||
getClass(), getKey(), line );
|
||||
}
|
||||
|
||||
final Attribute attribute;
|
||||
final ResourceLocation regKey = new ResourceLocation( args[0].trim() );
|
||||
if( !ForgeRegistries.ATTRIBUTES.containsKey( regKey ) ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Deleting entry. Invalid entry: {}",
|
||||
getClass(), getKey(), line ); // TODO note: I don't know if attributes will be registered at this point
|
||||
return null;
|
||||
}
|
||||
attribute = ForgeRegistries.ATTRIBUTES.getValue( regKey );
|
||||
|
||||
final int operator;
|
||||
if( args.length < 2 ) {
|
||||
SpecialMobs.LOG.warn( "Entry has no operator for {} \"{}\"! Replacing missing operator with +. Invalid entry: {}",
|
||||
getClass(), getKey(), line );
|
||||
operator = 1;
|
||||
}
|
||||
else {
|
||||
switch( args[1] ) {
|
||||
case "*": operator = 0;
|
||||
break;
|
||||
case "+": operator = 1;
|
||||
break;
|
||||
case "-": operator = -1;
|
||||
break;
|
||||
default: operator = 1;
|
||||
SpecialMobs.LOG.warn( "Entry has invalid operator {} for {} \"{}\"! Replacing operator with +. " +
|
||||
"Invalid entry: {}", args[1], getClass(), getKey(), line );
|
||||
break;
|
||||
}
|
||||
}
|
||||
final int identityValue = operator == 0 ? 1 : 0;
|
||||
|
||||
final double value;
|
||||
if( args.length < 3 ) {
|
||||
SpecialMobs.LOG.warn( "Entry has no value for {} \"{}\"! Replacing missing value with {}. Invalid entry: {}",
|
||||
getClass(), getKey(), identityValue, line );
|
||||
value = identityValue;
|
||||
}
|
||||
else {
|
||||
value = parseValue( args[2], line, identityValue );
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
return operator == 0 ? AttributeEntry.mult( attribute, value ) : AttributeEntry.add( attribute, value * operator );
|
||||
}
|
||||
|
||||
/** Parses a single value argument and returns a valid result. */
|
||||
private double parseValue( final String arg, final String line, final int identity ) {
|
||||
// Try to parse the value
|
||||
double value;
|
||||
try {
|
||||
value = Double.parseDouble( arg );
|
||||
}
|
||||
catch( NumberFormatException ex ) {
|
||||
// This is thrown if the string is not a parsable number
|
||||
SpecialMobs.LOG.warn( "Invalid value for {} \"{}\"! Falling back to {}. Invalid entry: {}",
|
||||
getClass(), getKey(), identity, line );
|
||||
value = identity;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -14,9 +14,8 @@ import java.util.List;
|
|||
@SuppressWarnings( "unused" )
|
||||
public class BlockListField extends GenericField<BlockList> {
|
||||
|
||||
/** Provides a detailed description of how to use entity lists. Recommended putting at the top of any file using entity lists. */
|
||||
@Override
|
||||
public List<String> verboseDescription() {
|
||||
/** Provides a detailed description of how to use block lists. Recommended putting at the top of any file using block lists. */
|
||||
public static List<String> verboseDescription() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Block List fields: General format = [ \"namespace:block_name[property1=value1,...]\", ... ]" );
|
||||
comment.add( " Block lists are arrays of blocks and partial block states." );
|
||||
|
|
|
@ -103,6 +103,8 @@ public class DoubleField extends AbstractConfigField {
|
|||
NON_NEGATIVE( 0.0, Double.POSITIVE_INFINITY ),
|
||||
/** Accepts any value between 0 and 1. */
|
||||
PERCENT( 0.0, 1.0 ),
|
||||
/** Accepts any value between -1 and 1. */
|
||||
SIGNED_PERCENT( -1.0, 1.0 ),
|
||||
/** Accepts any value between -1 and 2. */
|
||||
DROP_CHANCE( -1.0, 2.0 );
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
public static final String REG_KEY_DEFAULT = "default";
|
||||
|
||||
/** Provides a detailed description of how to use entity lists. Recommended to put at the top of any file using entity lists. */
|
||||
@Override
|
||||
public List<String> verboseDescription() {
|
||||
public static List<String> verboseDescription() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Entity List fields: General format = [ \"namespace:entity_type value1 value2 ...\", ... ]" );
|
||||
comment.add( " Entity lists are arrays of entity types. Some entity lists specify a number of values linked to each entity type." );
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a config field with an object value.
|
||||
* <p>
|
||||
|
@ -23,11 +20,6 @@ public abstract class GenericField<T> extends AbstractConfigField {
|
|||
super( key, description );
|
||||
valueDefault = defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> verboseDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return Returns the config field's value. */
|
||||
public T get() { return value; }
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.config.util.RegistryEntryList;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a config field with a registry entry list value.
|
||||
* <p>
|
||||
* See also: {@link net.minecraftforge.registries.ForgeRegistries}
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class RegistryEntryListField<T extends IForgeRegistryEntry<T>> extends GenericField<RegistryEntryList<T>> {
|
||||
|
||||
/** Provides a detailed description of how to use registry entry lists. Recommended putting at the top of any file using registry entry lists. */
|
||||
public static List<String> verboseDescription() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Registry Entry List fields: General format = [ \"namespace:entry_name\", ... ]" );
|
||||
comment.add( " Registry entry lists are arrays of registry keys. Many things in the game, such as blocks or potions, are defined" );
|
||||
comment.add( " by their registry key within a registry. For example, all items are registered in the \"minecraft:item\" registry." );
|
||||
comment.add( " An asterisk '*' can be used to match multiple registry keys. For example, 'minecraft:*' will match all vanilla entries" );
|
||||
comment.add( " within the registry entry list's target registry." );
|
||||
return comment;
|
||||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public RegistryEntryListField( String key, RegistryEntryList<T> defaultValue, String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
/** Adds info about the field type, format, and bounds to the end of a field's description. */
|
||||
public void appendFieldInfo( List<String> comment ) {
|
||||
comment.add( TomlHelper.fieldInfoFormat( "\"" + SpecialMobs.toString( valueDefault.getRegistry().getRegistryName() ) +
|
||||
"\" Registry List", valueDefault, "[ \"namespace:entry_name\", ... ]" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this field's value from the given raw toml value. If anything goes wrong, correct it at the lowest level possible.
|
||||
* <p>
|
||||
* For example, a missing value should be set to the default, while an out-of-range value should be adjusted to the
|
||||
* nearest in-range value
|
||||
*/
|
||||
@Override
|
||||
public void load( @Nullable Object raw ) {
|
||||
if( raw == null ) {
|
||||
value = valueDefault;
|
||||
return;
|
||||
}
|
||||
// All the actual loading is done through the objects
|
||||
value = new RegistryEntryList<>( this, valueDefault.getRegistry(), TomlHelper.parseStringList( raw ) );
|
||||
}
|
||||
}
|
|
@ -6,8 +6,7 @@ import com.electronwill.nightconfig.core.file.FileWatcher;
|
|||
import com.electronwill.nightconfig.core.io.CharacterOutput;
|
||||
import com.electronwill.nightconfig.core.io.ParsingException;
|
||||
import com.electronwill.nightconfig.core.io.WritingException;
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.GenericField;
|
||||
import fathertoast.specialmobs.common.config.field.*;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -338,13 +337,17 @@ public class ToastConfigSpec {
|
|||
/** @param comment The file comment to insert. */
|
||||
public void header( List<String> comment ) { ACTIONS.add( new Header( this, comment ) ); }
|
||||
|
||||
/** Inserts a detailed description of how to use the given field. */
|
||||
public void verboseFieldDesc( GenericField<?> field ) {
|
||||
final List<String> description = field.verboseDescription();
|
||||
|
||||
if( description != null && !description.isEmpty() )
|
||||
ACTIONS.add( new Comment( field.verboseDescription() ) );
|
||||
}
|
||||
/** Inserts a detailed description of how to use the registry entry list field. */
|
||||
public void describeRegistryEntryList() { ACTIONS.add( new Comment( RegistryEntryListField.verboseDescription() ) ); }
|
||||
|
||||
/** Inserts a detailed description of how to use the entity list field. */
|
||||
public void describeEntityList() { ACTIONS.add( new Comment( EntityListField.verboseDescription() ) ); }
|
||||
|
||||
/** Inserts a detailed description of how to use the attribute list field. */
|
||||
public void describeAttributeList() { ACTIONS.add( new Comment( AttributeListField.verboseDescription() ) ); }
|
||||
|
||||
/** Inserts a detailed description of how to use the block list field. */
|
||||
public void describeBlockList() { ACTIONS.add( new Comment( BlockListField.verboseDescription() ) ); }
|
||||
|
||||
/**
|
||||
* @param name The category name.
|
||||
|
|
|
@ -2,16 +2,16 @@ package fathertoast.specialmobs.common.config.file;
|
|||
|
||||
import com.electronwill.nightconfig.core.NullObject;
|
||||
import com.electronwill.nightconfig.core.utils.StringUtils;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class TomlHelper {
|
||||
private TomlHelper() {} // This is a static access only class that cannot be instantiated
|
||||
private TomlHelper() { } // This is a static access only class that cannot be instantiated
|
||||
|
||||
/** Attempts to convert a toml literal to a string list. May or may not be accurate. */
|
||||
public static List<String> parseStringList( Object value ) {
|
||||
|
@ -184,10 +184,10 @@ public final class TomlHelper {
|
|||
private static String fieldRangeNoLimit() { return "Any Value"; }
|
||||
|
||||
/** @return A range representation of toml literals with only an upper limit. */
|
||||
private static String fieldRangeUpperLimit( Number max ) { return Config.LESS_OR_EQUAL + " " + toLiteral( max ); }
|
||||
private static String fieldRangeUpperLimit( Number max ) { return ConfigUtil.LESS_OR_EQUAL + " " + toLiteral( max ); }
|
||||
|
||||
/** @return A range representation of toml literals with only a lower limit. */
|
||||
private static String fieldRangeLowerLimit( Number min ) { return Config.GREATER_OR_EQUAL + " " + toLiteral( min ); }
|
||||
private static String fieldRangeLowerLimit( Number min ) { return ConfigUtil.GREATER_OR_EQUAL + " " + toLiteral( min ); }
|
||||
|
||||
/** @return A range representation of toml literals with both a lower and upper limit. */
|
||||
private static String fieldRangeInterval( Number min, Number max ) { return toLiteral( min ) + " ~ " + toLiteral( max ); }
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for blazes.
|
||||
*/
|
||||
public class BlazeSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Blazes BLAZES;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public BlazeSpeciesConfig( MobFamily.Species<?> species, int fireballBurstCount, int fireballBurstDelay ) {
|
||||
super( species );
|
||||
|
||||
BLAZES = new Blazes( SPEC, species, speciesName, fireballBurstCount, fireballBurstDelay );
|
||||
}
|
||||
|
||||
public static class Blazes extends Config.AbstractCategory {
|
||||
|
||||
public final IntField fireballBurstCount;
|
||||
public final IntField fireballBurstDelay;
|
||||
|
||||
Blazes( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, int burstCount, int burstDelay ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
fireballBurstCount = SPEC.define( new IntField( "fireball_attack.burst_count", burstCount, IntField.Range.NON_NEGATIVE,
|
||||
"The number of fireballs " + speciesName + " launch with each burst." ) );
|
||||
fireballBurstDelay = SPEC.define( new IntField( "fireball_attack.burst_delay", burstDelay, IntField.Range.NON_NEGATIVE,
|
||||
"The time (in ticks) " + speciesName + " wait between each fireball in a burst. (20 ticks = 1 second)" ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for creepers.
|
||||
*/
|
||||
public class CreeperSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Creepers CREEPERS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public CreeperSpeciesConfig( MobFamily.Species<?> species,
|
||||
boolean cannotExplodeWhileWet, boolean explodeWhileBurning, boolean explodeWhenShot ) {
|
||||
super( species );
|
||||
|
||||
CREEPERS = new Creepers( SPEC, species, speciesName, cannotExplodeWhileWet, explodeWhileBurning, explodeWhenShot );
|
||||
}
|
||||
|
||||
public static class Creepers extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField stormChargeChance;
|
||||
|
||||
/** Note that this is inverted from how it is normally seen and used elsewhere. This is to avoid double-negatives in the config. */
|
||||
public final BooleanField canExplodeWhileWet;
|
||||
public final BooleanField explodesWhileBurning;
|
||||
public final BooleanField explodesWhenShot;
|
||||
|
||||
Creepers( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName,
|
||||
boolean cannotExplodeWhileWet, boolean explodeWhileBurning, boolean explodeWhenShot ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
stormChargeChance = SPEC.define( new DoubleField( "storm_charge_chance", -1.0, DoubleField.Range.SIGNED_PERCENT,
|
||||
"Chance for " + speciesName + " to spawn charged during thunderstorms.",
|
||||
"If this is set to a non-negative value, it overrides the value set for \"family_storm_charge_chance\"." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
canExplodeWhileWet = SPEC.define( new BooleanField( "can_explode_while_wet", !cannotExplodeWhileWet,
|
||||
"If true, " + speciesName + " can explode while wet (normal creeper behavior)." ) );
|
||||
explodesWhileBurning = SPEC.define( new BooleanField( "explodes_while_burning", explodeWhileBurning,
|
||||
"If true, " + speciesName + " will explode while burning. If extinguished before the fuse runs",
|
||||
"out, they will resume normal behavior." ) );
|
||||
explodesWhenShot = SPEC.define( new BooleanField( "explodes_when_shot", explodeWhenShot,
|
||||
"If true, " + speciesName + " will explode when hit by an indirect attack (e.g. an arrow)." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class MotherSpiderSpeciesConfig extends SpiderSpeciesConfig {
|
||||
|
||||
public final Mother MOTHER;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public MotherSpiderSpeciesConfig( MobFamily.Species<?> species, double spitChance,
|
||||
int minBabies, int maxBabies, int minExtraBabies, int maxExtraBabies ) {
|
||||
super( species, spitChance );
|
||||
|
||||
MOTHER = new Mother( SPEC, species, speciesName, minBabies, maxBabies, minExtraBabies, maxExtraBabies );
|
||||
}
|
||||
|
||||
public static class Mother extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange babies;
|
||||
|
||||
public final IntField.RandomRange extraBabies;
|
||||
|
||||
Mother( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName,
|
||||
int minBabies, int maxBabies, int minExtraBabies, int maxExtraBabies ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
babies = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "babies.min", minBabies, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of babies " + speciesName + " spawn on death.",
|
||||
"Any remaining 'extra babies' will added to the amount spawned on death (see below)." ) ),
|
||||
SPEC.define( new IntField( "babies.max", maxBabies, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
extraBabies = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "extra_babies.min", minExtraBabies, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of babies that " + speciesName + " can spawn from hits before death.",
|
||||
"Any remaining 'extra babies' will added to the amount spawned on death (see above)." ) ),
|
||||
SPEC.define( new IntField( "extra_babies.max", maxExtraBabies, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class QueenGhastSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Queen QUEEN;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public QueenGhastSpeciesConfig( MobFamily.Species<?> species, int minBabies, int maxBabies, int minSummons, int maxSummons ) {
|
||||
super( species );
|
||||
|
||||
QUEEN = new Queen( SPEC, species, speciesName, minBabies, maxBabies, minSummons, maxSummons );
|
||||
}
|
||||
|
||||
public static class Queen extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange babies;
|
||||
|
||||
public final IntField.RandomRange summons;
|
||||
|
||||
Queen( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName,
|
||||
int minBabies, int maxBabies, int minSummons, int maxSummons ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
babies = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "babies.min", minBabies, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of babies " + speciesName + " spawn on death." ) ),
|
||||
SPEC.define( new IntField( "babies.max", maxBabies, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
summons = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "summons.min", minSummons, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of times " + speciesName + " can summon minions." ) ),
|
||||
SPEC.define( new IntField( "summons.max", maxSummons, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for silverfish.
|
||||
*/
|
||||
public class SilverfishSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Silverfish SILVERFISH;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SilverfishSpeciesConfig( MobFamily.Species<?> species, double spitChance ) {
|
||||
super( species );
|
||||
|
||||
SILVERFISH = new Silverfish( SPEC, species, speciesName, spitChance );
|
||||
}
|
||||
|
||||
public static class Silverfish extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField aggressiveChance;
|
||||
|
||||
public final DoubleField spitterChance;
|
||||
|
||||
Silverfish( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, double spitChance ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
aggressiveChance = SPEC.define( new DoubleField( "aggressive_chance", -1.0, DoubleField.Range.SIGNED_PERCENT,
|
||||
"Chance for " + speciesName + " to spawn already calling for reinforcements.",
|
||||
"If this is set to a non-negative value, it overrides the value set for \"family_aggressive_chance\"." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
// Automatically set the default spitter chance to 0% if the mob has ranged attacks disabled by default
|
||||
final double effectiveDefault = species.bestiaryInfo.rangedAttackMaxRange > 0.0F ? spitChance : 0.0;
|
||||
spitterChance = SPEC.define( new DoubleField( "spitter_chance", effectiveDefault, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn as a 'spitter', which enables their ranged attack (if max range > 0)." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for skeletons and wither skeletons.
|
||||
*/
|
||||
public class SkeletonSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Skeletons SKELETONS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SkeletonSpeciesConfig( MobFamily.Species<?> species, double bowChance, double shieldChance ) {
|
||||
super( species );
|
||||
|
||||
SKELETONS = new Skeletons( SPEC, species, speciesName, bowChance, shieldChance );
|
||||
}
|
||||
|
||||
public static class Skeletons extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField bowEquipChance;
|
||||
|
||||
public final DoubleField shieldEquipChance;
|
||||
|
||||
Skeletons( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, double bowChance, double shieldChance ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
// Automatically set the default bow chance to 0% if the mob has ranged attacks disabled by default
|
||||
final double effectiveDefault = species.bestiaryInfo.rangedAttackMaxRange > 0.0F ? bowChance : 0.0;
|
||||
bowEquipChance = SPEC.define( new DoubleField( "bow_chance", effectiveDefault, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn with a bow, which enables their ranged attack (if max range > 0)." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
shieldEquipChance = SPEC.define( new DoubleField( "shield_chance", shieldChance, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn with a shield if they did not spawn with a bow.",
|
||||
"Shield users have a 33% chance to block frontal attacks (100% vs. long range attacks) and can be broken by axes." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.family.FamilyConfig;
|
||||
import fathertoast.specialmobs.common.config.field.*;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.potion.Effect;
|
||||
|
||||
/**
|
||||
* This is the base config for mob species. This may be extended to add categories specific to the species, but all
|
||||
* options that are used by all species should be defined in this class.
|
||||
*/
|
||||
public class SpeciesConfig extends Config.AbstractConfig {
|
||||
|
||||
public static final String SPECIAL_DATA_SUBCAT = "special_data.";
|
||||
|
||||
protected static String fileName( MobFamily.Species<?> species ) {
|
||||
return (species.specialVariantName == null ? "_normal" : ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ))
|
||||
+ "_" + ConfigUtil.noSpaces( species.family.configName );
|
||||
}
|
||||
|
||||
protected static String variantName( MobFamily.Species<?> species ) {
|
||||
return species.specialVariantName == null ? "vanilla replacement" : ConfigUtil.camelCaseToLowerSpace( species.specialVariantName );
|
||||
}
|
||||
|
||||
/** The full readable name for the species in lower space case; e.g., "baby cave spiders". */
|
||||
protected final String speciesName;
|
||||
|
||||
/** Category containing all options applicable to mob species as a whole; i.e. not specific to any particular species. */
|
||||
public final General GENERAL;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SpeciesConfig( MobFamily.Species<?> species ) {
|
||||
super( FamilyConfig.dir( species.family ), fileName( species ),
|
||||
String.format( "This config contains options that apply only to the %s %s species.",
|
||||
species.specialVariantName, ConfigUtil.camelCaseToLowerSpace( species.family.name ) ) );
|
||||
SPEC.newLine();
|
||||
SPEC.describeAttributeList();
|
||||
SPEC.describeRegistryEntryList();
|
||||
|
||||
speciesName = variantName( species ) + " " + species.family.configName;
|
||||
|
||||
GENERAL = new General( SPEC, species, speciesName );
|
||||
}
|
||||
|
||||
public static class General extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField randomScaling;
|
||||
|
||||
public final AttributeListField attributeChanges;
|
||||
|
||||
public final IntField experience;
|
||||
public final IntField healTime;
|
||||
public final DoubleField fallDamageMultiplier;
|
||||
public final BooleanField isImmuneToFire;
|
||||
public final BooleanField isImmuneToBurning;
|
||||
public final BooleanField canBreatheInWater;
|
||||
public final BooleanField ignoreWaterPush;
|
||||
public final BooleanField isDamagedByWater;
|
||||
public final BooleanField allowLeashing;
|
||||
public final BooleanField ignorePressurePlates;
|
||||
public final RegistryEntryListField<Block> immuneToStickyBlocks;
|
||||
public final RegistryEntryListField<Effect> immuneToPotions;
|
||||
|
||||
// These are at the end because they may or may not be present (not applicable for all families)
|
||||
public final DoubleField rangedAttackDamage;
|
||||
public final DoubleField rangedAttackSpread;
|
||||
public final DoubleField rangedWalkSpeed;
|
||||
public final IntField rangedAttackCooldown;
|
||||
public final IntField rangedAttackMaxCooldown;
|
||||
public final DoubleField rangedAttackMaxRange;
|
||||
|
||||
General( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName ) {
|
||||
super( parent, "general",
|
||||
"Options standard to all mob species (that is, not specific to any particular mob species)." );
|
||||
final BestiaryInfo info = species.bestiaryInfo;
|
||||
|
||||
randomScaling = SPEC.define( new DoubleField( "random_scaling", -1.0, DoubleField.Range.SIGNED_PERCENT,
|
||||
"When greater than 0, " + speciesName + " will have a random render scale applied. This is a visual effect only.",
|
||||
"If this is set to a non-negative value, it overrides the value set for both \"master_random_scaling\" and",
|
||||
"\"family_random_scaling\". The priority is species value > family value > master value." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
attributeChanges = SPEC.define( new AttributeListField( "attributes", info.defaultAttributes,
|
||||
"Attribute modifiers for " + speciesName + ". If no attribute changes are defined here, " + speciesName,
|
||||
"will have the exact same attributes as their parent vanilla mob." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
experience = SPEC.define( new IntField( SPECIAL_DATA_SUBCAT + "experience", info.experience, IntField.Range.NON_NEGATIVE,
|
||||
"The amount of experience " + speciesName + " drop when killed by a player. Multiplied by 2.5 for babies.",
|
||||
"Extra experience may drop based on equipment. Slime-style mobs also drop experience equal to slime size." ) );
|
||||
healTime = SPEC.define( new IntField( SPECIAL_DATA_SUBCAT + "heal_time", info.healTime, IntField.Range.NON_NEGATIVE,
|
||||
"If greater than 0, " + speciesName + " will heal 1 half-heart of health every \"heal_time\" ticks. (20 ticks = 1 second)" ) );
|
||||
fallDamageMultiplier = SPEC.define( new DoubleField( SPECIAL_DATA_SUBCAT + "fall_damage_multiplier", info.fallDamageMultiplier, DoubleField.Range.NON_NEGATIVE,
|
||||
"Fall damage taken by " + speciesName + " is multiplied by this value. 0 is fall damage immunity." ) );
|
||||
isImmuneToFire = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "immune_to_fire", info.isImmuneToFire,
|
||||
"If true, " + speciesName + " will take no fire damage. Does not affect spawn restrictions." ) );
|
||||
isImmuneToBurning = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "immune_to_burning", info.isImmuneToBurning,
|
||||
"If true, " + speciesName + " cannot be set on fire (this setting only matters if not immune to fire)." ) );
|
||||
canBreatheInWater = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "immune_to_drowning", info.canBreatheInWater,
|
||||
"If true, " + speciesName + " can breathe in water." ) );
|
||||
ignoreWaterPush = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "immune_to_fluid_push", info.ignoreWaterPush,
|
||||
"If true, " + speciesName + " will ignore forces applied by flowing fluids." ) );
|
||||
isDamagedByWater = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "sensitive_to_water", info.isDamagedByWater,
|
||||
"If true, " + speciesName + " will be continuously damaged while wet." ) );
|
||||
allowLeashing = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "allow_leashing", info.allowLeashing,
|
||||
"If true, " + speciesName + " can be leashed. (Note: Leashed mobs can still attack you.)" ) );
|
||||
ignorePressurePlates = SPEC.define( new BooleanField( SPECIAL_DATA_SUBCAT + "immune_to_pressure_plates", info.ignorePressurePlates,
|
||||
"If true, " + speciesName + " will not trigger pressure plates." ) );
|
||||
immuneToStickyBlocks = SPEC.define( new RegistryEntryListField<>( SPECIAL_DATA_SUBCAT + "immune_to_sticky_blocks", info.immuneToStickyBlocks,
|
||||
ConfigUtil.properCase( speciesName ) + " will not be 'trapped' in any blocks specified here (e.g. \"cobweb\" or \"sweet_berry_bush\")." ) );
|
||||
immuneToPotions = SPEC.define( new RegistryEntryListField<>( SPECIAL_DATA_SUBCAT + "immune_to_effects", info.immuneToPotions,
|
||||
ConfigUtil.properCase( speciesName ) + " cannot be inflicted with any effects specified here (e.g. \"instant_damage\" or \"regeneration\")." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
rangedAttackDamage = info.rangedAttackDamage < 0.0F ? null :
|
||||
SPEC.define( new DoubleField( SPECIAL_DATA_SUBCAT + "ranged_attack.damage", info.rangedAttackDamage, DoubleField.Range.NON_NEGATIVE,
|
||||
"" ) );
|
||||
rangedAttackSpread = info.rangedAttackSpread < 0.0F ? null :
|
||||
SPEC.define( new DoubleField( SPECIAL_DATA_SUBCAT + "ranged_attack.spread", info.rangedAttackSpread, DoubleField.Range.NON_NEGATIVE,
|
||||
"." ) );
|
||||
rangedWalkSpeed = info.rangedWalkSpeed < 0.0F ? null :
|
||||
SPEC.define( new DoubleField( SPECIAL_DATA_SUBCAT + "ranged_attack.walk_speed", info.rangedWalkSpeed, DoubleField.Range.NON_NEGATIVE,
|
||||
"." ) );
|
||||
rangedAttackCooldown = info.rangedAttackCooldown < 0 ? null :
|
||||
SPEC.define( new IntField( SPECIAL_DATA_SUBCAT + "ranged_attack.charge_time", info.rangedAttackCooldown, IntField.Range.NON_NEGATIVE,
|
||||
"The delay (in ticks) to 'charge up' and perform a ranged attack. (20 ticks = 1 second)" ) );
|
||||
rangedAttackMaxCooldown = info.rangedAttackMaxCooldown < 0 ? null :
|
||||
SPEC.define( new IntField( SPECIAL_DATA_SUBCAT + "ranged_attack.refire_time", info.rangedAttackMaxCooldown, IntField.Range.NON_NEGATIVE,
|
||||
"The total delay (in ticks) between each ranged attack. (20 ticks = 1 second)" ) );
|
||||
rangedAttackMaxRange = info.rangedAttackMaxRange < 0.0F ? null :
|
||||
SPEC.define( new DoubleField( SPECIAL_DATA_SUBCAT + "ranged_attack.max_range", info.rangedAttackMaxRange, DoubleField.Range.NON_NEGATIVE,
|
||||
"" ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for spiders and cave spiders.
|
||||
*/
|
||||
public class SpiderSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Spiders SPIDERS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SpiderSpeciesConfig( MobFamily.Species<?> species, double spitChance ) {
|
||||
super( species );
|
||||
|
||||
SPIDERS = new Spiders( SPEC, species, speciesName, spitChance );
|
||||
}
|
||||
|
||||
public static class Spiders extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField spitterChance;
|
||||
|
||||
Spiders( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, double spitChance ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
// Automatically set the default spitter chance to 0% if the mob has ranged attacks disabled by default
|
||||
final double effectiveDefault = species.bestiaryInfo.rangedAttackMaxRange > 0.0F ? spitChance : 0.0;
|
||||
spitterChance = SPEC.define( new DoubleField( "spitter_chance", effectiveDefault, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn as a 'spitter', which enables their ranged attack (if max range > 0)." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class SplittingCreeperSpeciesConfig extends CreeperSpeciesConfig {
|
||||
|
||||
public final Splitting SPLITTING;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public SplittingCreeperSpeciesConfig( MobFamily.Species<?> species,
|
||||
boolean cannotExplodeWhileWet, boolean explodeWhileBurning, boolean explodeWhenShot,
|
||||
int minExtraBabies, int maxExtraBabies ) {
|
||||
super( species, cannotExplodeWhileWet, explodeWhileBurning, explodeWhenShot );
|
||||
|
||||
SPLITTING = new Splitting( SPEC, species, speciesName, minExtraBabies, maxExtraBabies );
|
||||
}
|
||||
|
||||
public static class Splitting extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange extraBabies;
|
||||
|
||||
Splitting( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, int minExtraBabies, int maxExtraBabies ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
extraBabies = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "extra_babies.min", minExtraBabies, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of extra babies that " + speciesName + " spawn with their explosion.",
|
||||
"This is in addition to the number spawned based on explosion power." ) ),
|
||||
SPEC.define( new IntField( "extra_babies.max", maxExtraBabies, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class UndeadWitchSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Undead UNDEAD;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public UndeadWitchSpeciesConfig( MobFamily.Species<?> species, int minSummons, int maxSummons ) {
|
||||
super( species );
|
||||
|
||||
UNDEAD = new Undead( SPEC, species, speciesName, minSummons, maxSummons );
|
||||
}
|
||||
|
||||
public static class Undead extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange summons;
|
||||
|
||||
Undead( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, int minSummons, int maxSummons ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
summons = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "summons.min", minSummons, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of times " + speciesName + " can summon minions." ) ),
|
||||
SPEC.define( new IntField( "summons.max", maxSummons, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class WebSpiderSpeciesConfig extends SpiderSpeciesConfig {
|
||||
|
||||
public final Web WEB;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public WebSpiderSpeciesConfig( MobFamily.Species<?> species, double spitChance, int minWebs, int maxWebs ) {
|
||||
super( species, spitChance );
|
||||
|
||||
WEB = new Web( SPEC, species, speciesName, minWebs, maxWebs );
|
||||
}
|
||||
|
||||
public static class Web extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange webCount;
|
||||
|
||||
Web( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, int minWebs, int maxWebs ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
webCount = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "webs.min", minWebs, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of cobwebs " + speciesName + " can place." ) ),
|
||||
SPEC.define( new IntField( "webs.max", maxWebs, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class WildfireBlazeSpeciesConfig extends BlazeSpeciesConfig {
|
||||
|
||||
public final Wildfire WILDFIRE;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public WildfireBlazeSpeciesConfig( MobFamily.Species<?> species, int fireballBurstCount, int fireballBurstDelay,
|
||||
int minBabies, int maxBabies, int minSummons, int maxSummons ) {
|
||||
super( species, fireballBurstCount, fireballBurstDelay );
|
||||
|
||||
WILDFIRE = new Wildfire( SPEC, species, speciesName, minBabies, maxBabies, minSummons, maxSummons );
|
||||
}
|
||||
|
||||
public static class Wildfire extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange babies;
|
||||
|
||||
public final IntField.RandomRange summons;
|
||||
|
||||
Wildfire( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName,
|
||||
int minBabies, int maxBabies, int minSummons, int maxSummons ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
babies = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "babies.min", minBabies, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of babies " + speciesName + " spawn on death." ) ),
|
||||
SPEC.define( new IntField( "babies.max", maxBabies, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
summons = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "summons.min", minSummons, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of times " + speciesName + " can summon minions." ) ),
|
||||
SPEC.define( new IntField( "summons.max", maxSummons, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class WildsWitchSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Wilds WILDS;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public WildsWitchSpeciesConfig( MobFamily.Species<?> species, int minMounts, int maxMounts,
|
||||
int minSwarms, int maxSwarms, int minSwarmSize, int maxSwarmSize ) {
|
||||
super( species );
|
||||
|
||||
WILDS = new Wilds( SPEC, species, speciesName, minMounts, maxMounts, minSwarms, maxSwarms, minSwarmSize, maxSwarmSize );
|
||||
}
|
||||
|
||||
public static class Wilds extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange mounts;
|
||||
|
||||
public final IntField.RandomRange swarms;
|
||||
|
||||
public final IntField.RandomRange swarmSize;
|
||||
|
||||
Wilds( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName,
|
||||
int minMounts, int maxMounts, int minSwarms, int maxSwarms, int minSwarmSize, int maxSwarmSize ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
mounts = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "mounts.min", minMounts, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of times " + speciesName + " can summon a spider mount." ) ),
|
||||
SPEC.define( new IntField( "mounts.max", maxMounts, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
swarms = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "swarms.min", minSwarms, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of times " + speciesName + " can summon a spider swarm." ) ),
|
||||
SPEC.define( new IntField( "swarms.max", maxSwarms, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
swarmSize = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "swarm_size.min", minSwarmSize, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of spiders " + speciesName + " spawn with each swarm.",
|
||||
"Note that this is rolled on the summoner's spawn, not each time a swarm is summoned." ) ),
|
||||
SPEC.define( new IntField( "swarm_size.max", maxSwarmSize, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* This is the base species config for zombies, drowned, and zombified piglins.
|
||||
*/
|
||||
public class ZombieSpeciesConfig extends SpeciesConfig {
|
||||
|
||||
public final Zombies ZOMBIES;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public ZombieSpeciesConfig( MobFamily.Species<?> species, double bowChance, double shieldChance ) {
|
||||
super( species );
|
||||
|
||||
ZOMBIES = new Zombies( SPEC, species, speciesName, bowChance, shieldChance );
|
||||
}
|
||||
|
||||
public static class Zombies extends Config.AbstractCategory {
|
||||
|
||||
public final DoubleField bowEquipChance;
|
||||
|
||||
public final DoubleField shieldEquipChance;
|
||||
|
||||
Zombies( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, double bowChance, double shieldChance ) {
|
||||
super( parent, ConfigUtil.noSpaces( species.family.configName ),
|
||||
"Options standard to all " + species.family.configName + "." );
|
||||
|
||||
// Automatically set the default bow chance to 0% if the mob has ranged attacks disabled by default
|
||||
final double effectiveDefault = species.bestiaryInfo.rangedAttackMaxRange > 0.0F ? bowChance : 0.0;
|
||||
bowEquipChance = SPEC.define( new DoubleField( "bow_chance", effectiveDefault, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn with a bow, which enables their ranged attack (if max range > 0)." ) );
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
shieldEquipChance = SPEC.define( new DoubleField( "shield_chance", shieldChance, DoubleField.Range.PERCENT,
|
||||
"Chance for " + speciesName + " to spawn with a shield if they did not spawn with a bow.",
|
||||
"Shield users have a 33% chance to block frontal attacks (100% vs. long range attacks) and can be broken by axes." ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
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.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
/**
|
||||
* One attribute-operation-value entry in an attribute list.
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class AttributeEntry {
|
||||
/** The attribute this entry is defined for. */
|
||||
public final Attribute ATTRIBUTE;
|
||||
/** True if the value should be multiplied to the base attribute value (as opposed to added). */
|
||||
public final boolean MULTIPLY;
|
||||
/** The value given to this entry. */
|
||||
public final double VALUE;
|
||||
|
||||
/** The class this entry is defined for. This is not assigned until a world has been loaded. */
|
||||
Class<? extends Entity> entityClass;
|
||||
|
||||
/** Creates an entry with the specified values using the addition operation. Incompatible with move speed. Used for creating default configs. */
|
||||
public static AttributeEntry add( Attribute attribute, double value ) {
|
||||
if( attribute.equals( Attributes.MOVEMENT_SPEED ) )
|
||||
throw new IllegalArgumentException( "Move speed should not be added!" );
|
||||
return new AttributeEntry( attribute, false, value );
|
||||
}
|
||||
|
||||
/** Creates an entry with the specified values using the multiplication operation. Used for creating default configs. */
|
||||
public static AttributeEntry mult( Attribute attribute, double value ) { return new AttributeEntry( attribute, true, value ); }
|
||||
|
||||
/** Creates an entry with the specified values. */
|
||||
private AttributeEntry( Attribute attribute, boolean multiply, double value ) {
|
||||
ATTRIBUTE = attribute;
|
||||
MULTIPLY = multiply;
|
||||
VALUE = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The string representation of this entity list entry, as it would appear in a config file.
|
||||
* <p>
|
||||
* Format is "registry_key operation value", operation may be +, -, or *.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// Start with the attribute registry key
|
||||
ResourceLocation resource = ForgeRegistries.ATTRIBUTES.getKey( ATTRIBUTE );
|
||||
StringBuilder str = new StringBuilder( resource == null ? "null" : resource.toString() ).append( ' ' );
|
||||
// Append operation and value
|
||||
if( MULTIPLY ) str.append( "* " ).append( VALUE );
|
||||
else if( VALUE < 0.0 ) str.append( "- " ).append( -VALUE );
|
||||
else str.append( "+ " ).append( VALUE );
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/** Applies this attribute change to the entity attribute builder. */
|
||||
public void apply( AttributeModifierMap.MutableAttribute builder ) { apply( builder.builder.get( ATTRIBUTE ) ); }
|
||||
|
||||
/** Applies this attribute change to the entity. */
|
||||
public void apply( LivingEntity entity ) { apply( entity.getAttribute( ATTRIBUTE ) ); }
|
||||
|
||||
/** Applies this attribute change to the attribute instance. Assumes that the instance is for this entry's target attribute. */
|
||||
private void apply( ModifiableAttributeInstance attributeInstance ) {
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + ATTRIBUTE.getDescriptionId() );
|
||||
|
||||
if( MULTIPLY ) attributeInstance.setBaseValue( attributeInstance.getBaseValue() * VALUE );
|
||||
else attributeInstance.setBaseValue( attributeInstance.getBaseValue() + VALUE );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.IStringArray;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AttributeList implements IStringArray {
|
||||
/** The attribute-operation-value entries in this list. */
|
||||
private final AttributeEntry[] ENTRIES;
|
||||
|
||||
/**
|
||||
* Create a new attribute list from a list of entries.
|
||||
*/
|
||||
public AttributeList( List<AttributeEntry> entries ) { this( entries.toArray( new AttributeEntry[0] ) ); }
|
||||
|
||||
/**
|
||||
* Create a new entity list from an array of entries. Used for creating default configs.
|
||||
*/
|
||||
public AttributeList( AttributeEntry... entries ) { ENTRIES = entries; }
|
||||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() { return TomlHelper.toLiteral( toStringList().toArray() ); }
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
if( !(other instanceof AttributeList) ) return false;
|
||||
// Compare by the string list view of the object
|
||||
return toStringList().equals( ((AttributeList) other).toStringList() );
|
||||
}
|
||||
|
||||
/** @return A list of strings that will represent this object when written to a toml file. */
|
||||
@Override
|
||||
public List<String> toStringList() {
|
||||
// Create a list of the entries in string format
|
||||
final List<String> list = new ArrayList<>( ENTRIES.length );
|
||||
for( AttributeEntry entry : ENTRIES ) {
|
||||
list.add( entry.toString() );
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Applies all attribute changes in this list to the entity attribute builder. */
|
||||
public void apply( AttributeModifierMap.MutableAttribute builder ) {
|
||||
for( AttributeEntry entry : ENTRIES ) entry.apply( builder );
|
||||
}
|
||||
|
||||
/** Applies all attribute changes in this list to the entity. */
|
||||
public void apply( LivingEntity entity ) {
|
||||
for( AttributeEntry entry : ENTRIES ) entry.apply( entity );
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* One entity-value entry in an entity list.
|
||||
* One block state entry in a block list.
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class BlockEntry implements Cloneable {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
public abstract class ConfigUtil {
|
||||
|
||||
/** The plus or minus symbol (+/-). */
|
||||
public static final String PLUS_OR_MINUS = "\u00b1";
|
||||
/** The less than or equal to symbol (<=). */
|
||||
public static final String LESS_OR_EQUAL = "\u2264";
|
||||
/** The greater than or equal to symbol (>=). */
|
||||
public static final String GREATER_OR_EQUAL = "\u2265";
|
||||
|
||||
/** @return The string with all spaces replaced by underscores. Useful for file names. */
|
||||
public static String noSpaces( String str ) { return str.replace( ' ', '_' ); }
|
||||
|
||||
/** @return The string converted from camel case to lower space case; e.g., "UpperCamelCase" returns "upper camel case". */
|
||||
public static String camelCaseToLowerSpace( String str ) {
|
||||
final StringBuilder spacedStr = new StringBuilder();
|
||||
for( int i = 0; i < str.length(); i++ ) {
|
||||
final char c = str.charAt( i );
|
||||
if( Character.isUpperCase( c ) ) {
|
||||
if( i > 0 ) spacedStr.append( ' ' );
|
||||
spacedStr.append( Character.toLowerCase( c ) );
|
||||
}
|
||||
else {
|
||||
spacedStr.append( c );
|
||||
}
|
||||
}
|
||||
return spacedStr.toString();
|
||||
}
|
||||
|
||||
/** @return The string converted from camel case to lower underscore case; e.g., "UpperCamelCase" returns "upper_camel_case". */
|
||||
public static String camelCaseToLowerUnderscore( String str ) { return noSpaces( camelCaseToLowerSpace( str ) ); }
|
||||
|
||||
/** @return The string, but with the first character changed to upper case. */
|
||||
public static String properCase( String str ) { return str.substring( 0, 1 ).toUpperCase() + str.substring( 1 ); }
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.IStringArray;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A list of entries used to match registry entries. Can safely be loaded before its target registry is loaded, but
|
||||
* is not able to error check as well.
|
||||
* <p>
|
||||
* See also: {@link net.minecraftforge.registries.ForgeRegistries}
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class LazyRegistryEntryList<T extends IForgeRegistryEntry<T>> implements IStringArray {
|
||||
/** The registry this list acts as a subset of. */
|
||||
private final IForgeRegistry<T> REGISTRY;
|
||||
|
||||
/** The entries in this list. */
|
||||
private final Set<T> UNDERLYING_SET = new HashSet<>();
|
||||
/** The list used to write back to file. */
|
||||
private final List<String> PRINT_LIST = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new registry entry list from an array of entries. Used for creating default configs.
|
||||
* <p>
|
||||
* This method of creation can not take advantage of the * notation.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public LazyRegistryEntryList( IForgeRegistry<T> registry, T... entries ) {
|
||||
REGISTRY = registry;
|
||||
for( T entry : entries ) {
|
||||
if( UNDERLYING_SET.add( entry ) ) PRINT_LIST.add( SpecialMobs.toString( registry.getKey( entry ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new registry entry list from a list of registry key strings.
|
||||
*/
|
||||
public LazyRegistryEntryList( AbstractConfigField field, IForgeRegistry<T> registry, List<String> entries ) {
|
||||
REGISTRY = registry;
|
||||
for( String line : entries ) {
|
||||
if( line.endsWith( "*" ) ) {
|
||||
// Handle special case; add all entries in namespace
|
||||
if( !mergeFromNamespace( line.substring( 0, line.length() - 1 ) ) ) {
|
||||
// Don't delete this kind of entry
|
||||
SpecialMobs.LOG.warn( "Namespace entry for {} \"{}\" did not match anything! Questionable entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
}
|
||||
PRINT_LIST.add( line );
|
||||
}
|
||||
else {
|
||||
// Add a single registry entry
|
||||
final ResourceLocation regKey = new ResourceLocation( line );
|
||||
if( mergeFrom( regKey ) ) {
|
||||
PRINT_LIST.add( regKey.toString() );
|
||||
}
|
||||
else {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Deleting entry. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The registry this list draws from. */
|
||||
public IForgeRegistry<T> getRegistry() { return REGISTRY; }
|
||||
|
||||
/** @return The entries in this list. */
|
||||
public Set<T> getEntries() { return Collections.unmodifiableSet( UNDERLYING_SET ); }
|
||||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() {
|
||||
return TomlHelper.toLiteral( PRINT_LIST.toArray() );
|
||||
}
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
if( !(other instanceof LazyRegistryEntryList) ) return false;
|
||||
// Compare by the registries used and string list view of the object
|
||||
return getRegistry() == ((LazyRegistryEntryList<?>) other).getRegistry() &&
|
||||
toStringList().equals( ((LazyRegistryEntryList<?>) other).toStringList() );
|
||||
}
|
||||
|
||||
/** @return A list of strings that will represent this object when written to a toml file. */
|
||||
@Override
|
||||
public List<String> toStringList() { return PRINT_LIST; }
|
||||
|
||||
/** @return Returns true if there are no entries in this list. */
|
||||
public boolean isEmpty() { return UNDERLYING_SET.isEmpty(); }
|
||||
|
||||
/** @return Returns true if the entry is contained in this list. */
|
||||
public boolean contains( T entry ) { return UNDERLYING_SET.contains( entry ); }
|
||||
|
||||
/** @return Adds the registry entry if it exists and isn't already present, returns true if successful. */
|
||||
private boolean mergeFrom( ResourceLocation regKey ) {
|
||||
final T entry = REGISTRY.getValue( regKey );
|
||||
return entry != null && UNDERLYING_SET.add( entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param namespace Merges all registry entries with keys that start with a namespace into this list.
|
||||
* @return True if any registry entries were actually added.
|
||||
*/
|
||||
private boolean mergeFromNamespace( String namespace ) {
|
||||
boolean foundAny = false;
|
||||
for( ResourceLocation regKey : REGISTRY.getKeys() ) {
|
||||
if( regKey.toString().startsWith( namespace ) ) {
|
||||
if( mergeFrom( regKey ) ) foundAny = true;
|
||||
}
|
||||
}
|
||||
return foundAny;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.IStringArray;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A list of entries used to match registry entries.
|
||||
* <p>
|
||||
* See also: {@link net.minecraftforge.registries.ForgeRegistries}
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class RegistryEntryList<T extends IForgeRegistryEntry<T>> implements IStringArray {
|
||||
/** The registry this list acts as a subset of. */
|
||||
private final IForgeRegistry<T> REGISTRY;
|
||||
|
||||
/** The entries in this list. */
|
||||
private final Set<T> UNDERLYING_SET = new HashSet<>();
|
||||
/** The list used to write back to file. */
|
||||
private final List<String> PRINT_LIST = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new registry entry list from an array of entries. Used for creating default configs.
|
||||
* <p>
|
||||
* This method of creation can not take advantage of the * notation.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public RegistryEntryList( IForgeRegistry<T> registry, T... entries ) {
|
||||
REGISTRY = registry;
|
||||
for( T entry : entries ) {
|
||||
if( UNDERLYING_SET.add( entry ) ) PRINT_LIST.add( SpecialMobs.toString( registry.getKey( entry ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new registry entry list from a list of registry key strings.
|
||||
*/
|
||||
public RegistryEntryList( AbstractConfigField field, IForgeRegistry<T> registry, List<String> entries ) {
|
||||
REGISTRY = registry;
|
||||
for( String line : entries ) {
|
||||
if( line.endsWith( "*" ) ) {
|
||||
// Handle special case; add all entries in namespace
|
||||
if( !mergeFromNamespace( line.substring( 0, line.length() - 1 ) ) ) {
|
||||
// Don't delete this kind of entry
|
||||
SpecialMobs.LOG.warn( "Namespace entry for {} \"{}\" did not match anything! Questionable entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
}
|
||||
PRINT_LIST.add( line );
|
||||
}
|
||||
else {
|
||||
// Add a single registry entry
|
||||
final ResourceLocation regKey = new ResourceLocation( line );
|
||||
if( mergeFrom( regKey ) ) {
|
||||
PRINT_LIST.add( regKey.toString() );
|
||||
}
|
||||
else {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Deleting entry. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return The registry this list draws from. */
|
||||
public IForgeRegistry<T> getRegistry() { return REGISTRY; }
|
||||
|
||||
/** @return The entries in this list. */
|
||||
public Set<T> getEntries() { return Collections.unmodifiableSet( UNDERLYING_SET ); }
|
||||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() {
|
||||
return TomlHelper.toLiteral( PRINT_LIST.toArray() );
|
||||
}
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
if( !(other instanceof RegistryEntryList) ) return false;
|
||||
// Compare by the registries used and string list view of the object
|
||||
return getRegistry() == ((RegistryEntryList<?>) other).getRegistry() &&
|
||||
toStringList().equals( ((RegistryEntryList<?>) other).toStringList() );
|
||||
}
|
||||
|
||||
/** @return A list of strings that will represent this object when written to a toml file. */
|
||||
@Override
|
||||
public List<String> toStringList() { return PRINT_LIST; }
|
||||
|
||||
/** @return Returns true if there are no entries in this list. */
|
||||
public boolean isEmpty() { return UNDERLYING_SET.isEmpty(); }
|
||||
|
||||
/** @return Returns true if the entry is contained in this list. */
|
||||
public boolean contains( T entry ) { return UNDERLYING_SET.contains( entry ); }
|
||||
|
||||
/** @return Adds the registry entry if it exists and isn't already present, returns true if successful. */
|
||||
private boolean mergeFrom( ResourceLocation regKey ) {
|
||||
final T entry = REGISTRY.getValue( regKey );
|
||||
return entry != null && UNDERLYING_SET.add( entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param namespace Merges all registry entries with keys that start with a namespace into this list.
|
||||
* @return True if any registry entries were actually added.
|
||||
*/
|
||||
private boolean mergeFromNamespace( String namespace ) {
|
||||
boolean foundAny = false;
|
||||
for( ResourceLocation regKey : REGISTRY.getKeys() ) {
|
||||
if( regKey.toString().startsWith( namespace ) ) {
|
||||
if( mergeFrom( regKey ) ) foundAny = true;
|
||||
}
|
||||
}
|
||||
return foundAny;
|
||||
}
|
||||
}
|
|
@ -39,17 +39,19 @@ public class SpecialMobs {
|
|||
* o dimension-sensitive configs
|
||||
* o environment-sensitive configs
|
||||
* ? natural spawning
|
||||
* + potions
|
||||
* + vulnerability (opposite of resistance)
|
||||
* o entities
|
||||
* - nbt-driven capabilities (special mob data)
|
||||
* o fish hook
|
||||
* o bug projectile
|
||||
* o bug spit
|
||||
* + bestiary
|
||||
* ? configurable stats
|
||||
* - configurable stats
|
||||
* - monster families (see doc for specifics)
|
||||
* - creepers
|
||||
* - chance to spawn charged during thunderstorms
|
||||
* + scope
|
||||
* - zombies
|
||||
* - zombies TODO zombie villager renderer
|
||||
* o villager infection
|
||||
* + transformations
|
||||
* - ranged attack AI (using bow)
|
||||
|
@ -57,25 +59,28 @@ public class SpecialMobs {
|
|||
* + drowned
|
||||
* - zombified piglins
|
||||
* - ranged attack AI (using bow)
|
||||
* + ranged attack AI (using crossbow)
|
||||
* - use shields
|
||||
* - skeletons
|
||||
* - use shields
|
||||
* - melee chance
|
||||
* - babies
|
||||
* - wither skeletons
|
||||
* - use shields
|
||||
* - bow chance
|
||||
* - babies
|
||||
* - slimes
|
||||
* - smallest size can deal damage
|
||||
* - magma cubes
|
||||
* - spiders
|
||||
* o ranged attack AI
|
||||
* o ranged attack AI (spitter)
|
||||
* - cave spiders
|
||||
* o ranged attack AI
|
||||
* o ranged attack AI (spitter)
|
||||
* - silverfish
|
||||
* ? ranged attack AI
|
||||
* + ranged attack AI (spitter)
|
||||
* + puffer
|
||||
* - endermen
|
||||
* - witches
|
||||
* - witches TODO inject ranged attack stats
|
||||
* - ability to equip held items
|
||||
* - uses splash speed instead of regular
|
||||
* - ghasts
|
||||
|
@ -109,6 +114,8 @@ public class SpecialMobs {
|
|||
|
||||
public SpecialMobs() {
|
||||
Config.initialize();
|
||||
MobFamily.initBestiary();
|
||||
|
||||
packetHandler.registerMessages();
|
||||
|
||||
//MinecraftForge.EVENT_BUS.register( new SMEventListener() );
|
||||
|
@ -121,8 +128,6 @@ public class SpecialMobs {
|
|||
|
||||
SMEntities.REGISTRY.register( eventBus );
|
||||
SMItems.REGISTRY.register( eventBus );
|
||||
|
||||
MobFamily.initBestiary();
|
||||
}
|
||||
|
||||
// TODO - This could very well help out the config malformation issue
|
||||
|
|
|
@ -7,6 +7,7 @@ import fathertoast.specialmobs.common.util.AnnotationHelper;
|
|||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityClassification;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraftforge.event.entity.EntityAttributeCreationEvent;
|
||||
import net.minecraftforge.fml.RegistryObject;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
|
@ -15,10 +16,10 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
public class SMEntities {
|
||||
|
||||
public static final DeferredRegister<EntityType<?>> REGISTRY = DeferredRegister.create( ForgeRegistries.ENTITIES, SpecialMobs.MOD_ID );
|
||||
|
||||
|
||||
/** Misc entities */
|
||||
public static final RegistryObject<EntityType<CorporealShiftFireballEntity>> CORPOREAL_FIREBALL = register("corporeal_shift_fireball",
|
||||
EntityType.Builder.<CorporealShiftFireballEntity>of(CorporealShiftFireballEntity::new, EntityClassification.MISC).sized(1.0F, 1.0F).clientTrackingRange(4).updateInterval(3));
|
||||
public static final RegistryObject<EntityType<CorporealShiftFireballEntity>> CORPOREAL_FIREBALL = register( "corporeal_shift_fireball",
|
||||
EntityType.Builder.<CorporealShiftFireballEntity>of( CorporealShiftFireballEntity::new, EntityClassification.MISC ).sized( 1.0F, 1.0F ).clientTrackingRange( 4 ).updateInterval( 3 ) );
|
||||
|
||||
/** Registers an entity type to the deferred register. */
|
||||
public static <T extends Entity> RegistryObject<EntityType<T>> register( String name, EntityType.Builder<T> builder ) {
|
||||
|
@ -28,8 +29,11 @@ public class SMEntities {
|
|||
/** Sets the default attributes for entity types, such as max health, attack damage etc. */
|
||||
public static void createAttributes( EntityAttributeCreationEvent event ) {
|
||||
// Bestiary-generated entities
|
||||
for( MobFamily.Species<?> species : MobFamily.getAllSpecies() )
|
||||
event.put( species.entityType.get(), AnnotationHelper.createAttributes( species ) );
|
||||
for( MobFamily.Species<?> species : MobFamily.getAllSpecies() ) {
|
||||
final AttributeModifierMap.MutableAttribute attributes = AnnotationHelper.createAttributes( species );
|
||||
species.config.GENERAL.attributeChanges.apply( attributes );
|
||||
event.put( species.entityType.get(), attributes.build() );
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the natural spawn placement rules for entity types. */
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package fathertoast.specialmobs.common.entity;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.pathfinding.PathNodeType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface ISpecialMob<T extends LivingEntity & ISpecialMob<T>> {
|
||||
|
||||
/** @return This mob's special data. */
|
||||
SpecialMobData<T> getSpecialData();
|
||||
|
||||
/** @return This mob's species. */
|
||||
MobFamily.Species<? extends T> getSpecies();
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
int getExperience();
|
||||
|
||||
|
@ -16,7 +20,4 @@ public interface ISpecialMob<T extends LivingEntity & ISpecialMob<T>> {
|
|||
|
||||
/** Sets the entity's pathfinding malus for a particular node type; negative value is un-walkable. */
|
||||
void setPathfindingMalus( PathNodeType nodeType, float malus );
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
ResourceLocation[] getDefaultTextures();
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
package fathertoast.specialmobs.common.entity;
|
||||
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.entity.creeper._SpecialCreeperEntity;
|
||||
import net.minecraft.block.FlowingFluidBlock;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.CreatureAttribute;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.monster.CreeperEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.projectile.AbstractArrowEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
|
@ -52,6 +54,16 @@ public final class MobHelper {
|
|||
new EffectInstance( Effects.POISON, 1, 0 ) // Keep this option last for easy disable (by cave spiders)
|
||||
};
|
||||
|
||||
/** Charges a creeper, potentially supercharging it. */
|
||||
public static void charge( CreeperEntity creeper ) {
|
||||
if( creeper instanceof _SpecialCreeperEntity ) {
|
||||
((_SpecialCreeperEntity) creeper).charge();
|
||||
}
|
||||
else {
|
||||
creeper.getEntityData().set( CreeperEntity.DATA_IS_POWERED, true );
|
||||
}
|
||||
}
|
||||
|
||||
/** @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 ) {
|
||||
|
@ -184,8 +196,8 @@ public final class MobHelper {
|
|||
public static EffectInstance nextPlagueEffect( Random random, World world ) {
|
||||
final int duration = MobHelper.getDebuffDuration( world.getDifficulty() );
|
||||
|
||||
//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 )];
|
||||
final EffectInstance potion = PLAGUE_EFFECTS[random.nextInt( PLAGUE_EFFECTS.length -
|
||||
(Config.MAIN.GENERAL.enableNausea.get() ? 0 : 1) )];
|
||||
return new EffectInstance( potion.getEffect(), duration * potion.getDuration(), potion.getAmplifier() );
|
||||
}
|
||||
|
||||
|
@ -248,7 +260,7 @@ public final class MobHelper {
|
|||
Vector3d targetVec = sourcePos.vectorTo( blocker.position() ).normalize();
|
||||
targetVec = new Vector3d( targetVec.x, 0.0, targetVec.z );
|
||||
if( targetVec.dot( lookVec ) < 0.0 ) {
|
||||
blocker.level.playSound(null, blocker.getX() + 0.5D, blocker.getY(), blocker.getZ() + 0.5D, SoundEvents.SHIELD_BLOCK, SoundCategory.NEUTRAL, 0.9F, 1.0F);
|
||||
blocker.level.playSound( null, blocker.getX() + 0.5D, blocker.getY(), blocker.getZ() + 0.5D, SoundEvents.SHIELD_BLOCK, SoundCategory.NEUTRAL, 0.9F, 1.0F );
|
||||
if( needsShield && entity instanceof PlayerEntity ) {
|
||||
maybeDestroyShield( blocker, shield, shieldHand, ((PlayerEntity) entity).getMainHandItem() );
|
||||
}
|
||||
|
@ -268,7 +280,7 @@ public final class MobHelper {
|
|||
private static void maybeDestroyShield( LivingEntity blocker, ItemStack shield, Hand shieldHand, ItemStack weapon ) {
|
||||
if( !weapon.isEmpty() && !shield.isEmpty() && weapon.getItem() instanceof AxeItem && shield.getItem() == Items.SHIELD &&
|
||||
blocker.getRandom().nextFloat() < 0.25F - EnchantmentHelper.getBlockEfficiency( blocker ) * 0.05F ) {
|
||||
blocker.level.playSound(null, blocker.getX() + 0.5D, blocker.getY(), blocker.getZ() + 0.5D, SoundEvents.SHIELD_BREAK, SoundCategory.NEUTRAL, 0.9F, 1.0F);
|
||||
blocker.level.playSound( null, blocker.getX() + 0.5D, blocker.getY(), blocker.getZ() + 0.5D, SoundEvents.SHIELD_BREAK, SoundCategory.NEUTRAL, 0.9F, 1.0F );
|
||||
blocker.broadcastBreakEvent( shieldHand );
|
||||
blocker.setItemInHand( shieldHand, ItemStack.EMPTY );
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package fathertoast.specialmobs.common.entity;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.CreatureAttribute;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.monster.SpiderEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.StringNBT;
|
||||
|
@ -14,11 +16,12 @@ import net.minecraft.network.datasync.DataParameter;
|
|||
import net.minecraft.pathfinding.PathNodeType;
|
||||
import net.minecraft.potion.Effect;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.entity.living.PotionEvent;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static fathertoast.specialmobs.common.util.References.*;
|
||||
|
@ -47,11 +50,6 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
/** Data manager parameter for render scale. */
|
||||
private final DataParameter<Float> renderScale;
|
||||
|
||||
/** The base collision box scale of this variant's family. */
|
||||
private final float familyScale;
|
||||
/** The base collision box scale of this variant. */
|
||||
private float baseScale;
|
||||
|
||||
/** The base texture of the entity. */
|
||||
private ResourceLocation texture;
|
||||
/** The glowing eyes texture of the entity. */
|
||||
|
@ -61,43 +59,17 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
/** True if the textures need to be sent to the client. */
|
||||
private boolean updateTextures;
|
||||
|
||||
/** The damage the entity uses for its ranged attacks, when applicable. */
|
||||
public float rangedAttackDamage;
|
||||
/** The spread (inaccuracy) of the entity's ranged attacks. */
|
||||
public float rangedAttackSpread = 1.0F;
|
||||
/** The movement speed multiplier the entity uses during its ranged attack ai. Requires an AI reload to take effect. */
|
||||
public float rangedWalkSpeed = 1.0F;
|
||||
/** The delay (in ticks) before a new ranged attack can begin after firing. Requires an AI reload to take effect. */
|
||||
public int rangedAttackCooldown;
|
||||
/**
|
||||
* The delay (in ticks) between each ranged attack at maximum delay. Requires an AI reload to take effect.
|
||||
* Unused for bow attacks. For fireball attacks, this is the cooldown + charge time.
|
||||
* For all other attacks, this is the cooldown at maximum range (scaled down to the minimum cooldown at point-blank).
|
||||
*/
|
||||
public int rangedAttackMaxCooldown;
|
||||
/**
|
||||
* The maximum distance (in blocks) the entity can fire ranged attacks from. Requires an ai reload to take effect.
|
||||
* Ranged ai can only be used if this stat is greater than 0. Does not change aggro range.
|
||||
*/
|
||||
public float rangedAttackMaxRange;
|
||||
|
||||
/** The rate this mob regenerates health (ticks per 1 health). Off if 0 or less. */
|
||||
private int healTimeMax;
|
||||
/** Counter to the next heal, if healTimeMax is greater than 0. */
|
||||
private int healTime;
|
||||
|
||||
/** Proportion of fall damage taken. */
|
||||
private float fallDamageMultiplier = 1.0F;
|
||||
|
||||
private float fallDamageMultiplier;
|
||||
/** Whether the entity is immune to fire damage. */
|
||||
private boolean isImmuneToFire;
|
||||
/** Whether the entity is immune to being set on fire. */
|
||||
private boolean isImmuneToBurning;
|
||||
/** Whether the entity can be leashed. */
|
||||
private boolean allowLeashing;
|
||||
/** Whether the entity does not trigger pressure plates. */
|
||||
private boolean ignorePressurePlates;
|
||||
|
||||
/** Whether the entity can breathe under water. */
|
||||
private boolean canBreatheInWater;
|
||||
/** Whether the entity can ignore pushing from flowing water. */
|
||||
|
@ -105,44 +77,79 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
/** Whether the entity is damaged when wet. */
|
||||
private boolean isDamagedByWater;
|
||||
|
||||
/** List of blocks that the entity cannot be stuck in. */
|
||||
private final HashSet<String> immuneToStickyBlocks = new HashSet<>();
|
||||
/** List of potions that cannot be applied to the entity. */
|
||||
private final HashSet<String> immuneToPotions = new HashSet<>();
|
||||
/** Whether the entity can be leashed. */
|
||||
private boolean allowLeashing;
|
||||
/** Whether the entity does not trigger pressure plates. */
|
||||
private boolean ignorePressurePlates;
|
||||
/** Set of blocks that the entity cannot be stuck in. */
|
||||
private final HashSet<Block> immuneToStickyBlocks = new HashSet<>();
|
||||
/** Set of potions that cannot be applied to the entity. */
|
||||
private final HashSet<Effect> immuneToPotions = new HashSet<>();
|
||||
|
||||
/** The damage the entity uses for its ranged attacks, when applicable. */
|
||||
private float rangedAttackDamage;
|
||||
/** The spread (inaccuracy) of the entity's ranged attacks. */
|
||||
private float rangedAttackSpread;
|
||||
/** The movement speed multiplier the entity uses during its ranged attack ai. Requires an AI reload to take effect. */
|
||||
private float rangedWalkSpeed;
|
||||
/** The delay (in ticks) before a ranged attack can be used. Requires an AI reload to take effect. */
|
||||
private int rangedAttackCooldown;
|
||||
/**
|
||||
* The delay (in ticks) between each ranged attack at maximum delay. Requires an AI reload to take effect.
|
||||
* Unused for bow attacks. For fireball attacks, this is "refire" time.
|
||||
* For spit attacks, this is the cooldown at maximum range (scaled down to the minimum cooldown at point-blank).
|
||||
*/
|
||||
private int rangedAttackMaxCooldown;
|
||||
/**
|
||||
* The maximum distance (in blocks) the entity can fire ranged attacks from. Requires an ai reload to take effect.
|
||||
* Ranged ai can only be used if this stat is greater than 0. Does not change aggro range.
|
||||
*/
|
||||
private float rangedAttackMaxRange;
|
||||
|
||||
/**
|
||||
* Constructs a SpecialMobData to store generic data about a mob.
|
||||
* <p>
|
||||
* This constructor should be called during data watcher definitions, and defining the 'render scale' data watcher
|
||||
* parameter is the only thing actually done while constructing.
|
||||
* parameter and setting up AI stats are the only things actually done while constructing.
|
||||
* <p>
|
||||
* The #initialize() method must be called later on to complete initialization (e.g. in the entity constructor).
|
||||
* The #initialize() method must be called later on to complete initialization (in the entity constructor).
|
||||
*
|
||||
* @param entity The entity to store data for.
|
||||
* @param scale Data parameter for storing the render scale.
|
||||
* @param familyBaseScale Base render scale. Typically 1.0F.
|
||||
* @param entity The entity to store data for.
|
||||
* @param scale Data parameter for storing the render scale.
|
||||
*/
|
||||
public SpecialMobData( T entity, DataParameter<Float> scale, float familyBaseScale ) {
|
||||
public SpecialMobData( T entity, DataParameter<Float> scale ) {
|
||||
theEntity = entity;
|
||||
renderScale = scale;
|
||||
|
||||
familyScale = baseScale = familyBaseScale;
|
||||
|
||||
setTextures( entity.getDefaultTextures() );
|
||||
|
||||
entity.getEntityData().define( renderScale, nextScale() );
|
||||
|
||||
final SpeciesConfig.General config = theEntity.getSpecies().config.GENERAL;
|
||||
setRangedAttackDamage( config.rangedAttackDamage == null ? -1.0F : (float) config.rangedAttackDamage.get() );
|
||||
setRangedAttackSpread( config.rangedAttackSpread == null ? -1.0F : (float) config.rangedAttackSpread.get() );
|
||||
setRangedWalkSpeed( config.rangedWalkSpeed == null ? -1.0F : (float) config.rangedWalkSpeed.get() );
|
||||
setRangedAttackCooldown( config.rangedAttackCooldown == null ? -1 : config.rangedAttackCooldown.get() );
|
||||
setRangedAttackMaxCooldown( config.rangedAttackMaxCooldown == null ? -1 : config.rangedAttackMaxCooldown.get() );
|
||||
setRangedAttackMaxRange( config.rangedAttackMaxRange == null ? -1.0F : (float) config.rangedAttackMaxRange.get() );
|
||||
}
|
||||
|
||||
/** Called to finish initialization, since we can only define data watcher params in the constructor. */
|
||||
public void initialize() {
|
||||
setImmuneToFire( theEntity.getType().fireImmune() );
|
||||
if( theEntity.getMobType() == CreatureAttribute.UNDEAD ) {
|
||||
addPotionImmunity( Effects.REGENERATION, Effects.POISON );
|
||||
}
|
||||
if( theEntity instanceof SpiderEntity ) {
|
||||
addStickyBlockImmunity( Blocks.COBWEB );
|
||||
addPotionImmunity( Effects.POISON );
|
||||
}
|
||||
final BestiaryInfo info = theEntity.getSpecies().bestiaryInfo;
|
||||
texture = info.texture;
|
||||
textureEyes = info.eyesTexture;
|
||||
textureOverlay = info.overlayTexture;
|
||||
|
||||
final SpeciesConfig.General config = theEntity.getSpecies().config.GENERAL;
|
||||
theEntity.setExperience( config.experience.get() );
|
||||
setRegenerationTime( config.healTime.get() );
|
||||
setFallDamageMultiplier( (float) config.fallDamageMultiplier.get() );
|
||||
setImmuneToFire( config.isImmuneToFire.get() );
|
||||
setImmuneToBurning( config.isImmuneToBurning.get() );
|
||||
setCanBreatheInWater( config.canBreatheInWater.get() );
|
||||
setIgnoreWaterPush( config.ignoreWaterPush.get() );
|
||||
setDamagedByWater( config.isDamagedByWater.get() );
|
||||
setAllowLeashing( config.allowLeashing.get() );
|
||||
setIgnorePressurePlates( config.ignorePressurePlates.get() );
|
||||
addStickyBlockImmunity( config.immuneToStickyBlocks.get().getEntries() );
|
||||
addPotionImmunity( config.immuneToPotions.get().getEntries() );
|
||||
}
|
||||
|
||||
/** Copies all of the data from another mob, optionally copying texture(s). */
|
||||
|
@ -177,43 +184,29 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this entity has a glowing eyes texture.
|
||||
*/
|
||||
/** @return Whether this entity has a glowing eyes texture. */
|
||||
public boolean hasEyesTexture() { return textureEyes != null; }
|
||||
|
||||
/**
|
||||
* @return Whether this entity has an overlay texture.
|
||||
*/
|
||||
/** @return Whether this entity has an overlay texture. */
|
||||
public boolean hasOverlayTexture() { return textureOverlay != null; }
|
||||
|
||||
/**
|
||||
* @return The base texture for the entity.
|
||||
*/
|
||||
/** @return The base texture for the entity. */
|
||||
public ResourceLocation getTexture() { return texture; }
|
||||
|
||||
/**
|
||||
* @return The glowing eyes texture for the entity.
|
||||
*/
|
||||
/** @return The glowing eyes texture for the entity. */
|
||||
public ResourceLocation getTextureEyes() { return textureEyes; }
|
||||
|
||||
/**
|
||||
* @return The overlay texture for the entity.
|
||||
*/
|
||||
/** @return The overlay texture for the entity. */
|
||||
public ResourceLocation getTextureOverlay() { return textureOverlay; }
|
||||
|
||||
/**
|
||||
* @param textures The new texture(s) to set for the entity.
|
||||
*/
|
||||
/** @param textures The new texture(s) to set for the entity. */
|
||||
private void setTextures( ResourceLocation[] textures ) {
|
||||
texture = textures[0];
|
||||
textureEyes = textures.length > 1 ? textures[1] : null;
|
||||
textureOverlay = textures.length > 2 ? textures[2] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param textures The new texture(s) to load for the entity. Called when loaded from a packet.
|
||||
*/
|
||||
/** @param textures The new texture(s) to load for the entity. Called when loaded from a packet. */
|
||||
public void loadTextures( String[] textures ) {
|
||||
try {
|
||||
loadTexture( textures[0] );
|
||||
|
@ -275,42 +268,51 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
/** @return The render scale for the entity. */
|
||||
/** @return The render scale for the entity, including any applied random scaling. */
|
||||
public float getRenderScale() { return theEntity.getEntityData().get( renderScale ); }
|
||||
|
||||
/** Sets the overall render scale for the entity. */
|
||||
public void setRenderScale( float scale ) {
|
||||
if( !theEntity.level.isClientSide ) {
|
||||
theEntity.getEntityData().set( renderScale, scale );
|
||||
}
|
||||
if( !theEntity.level.isClientSide ) theEntity.getEntityData().set( renderScale, scale );
|
||||
}
|
||||
|
||||
public float getFamilyBaseScale() { return familyScale; }
|
||||
//** @return The base render scale for the entity's mob family. */
|
||||
//public float getFamilyBaseScale() { return familyScale; }
|
||||
|
||||
public float getBaseScaleForPreScaledValues() { return getBaseScale() / getFamilyBaseScale(); }
|
||||
//** @return The render scale for the entity without its family scale factored in; used to correct scaling for pre-scaled vanilla values. */
|
||||
//public float getBaseScaleForPreScaledValues() { return getBaseScale() / getFamilyBaseScale(); }
|
||||
|
||||
public float getBaseScale() { return baseScale; }
|
||||
|
||||
public void setBaseScale( float newBaseScale ) {
|
||||
baseScale = newBaseScale;
|
||||
setRenderScale( nextScale() );
|
||||
}
|
||||
/** @return The base render scale for the entity, which is a property of the mob species. */
|
||||
public float getBaseScale() { return theEntity.getSpecies().bestiaryInfo.baseScale; }
|
||||
|
||||
/** @return A random render scale based on config settings. */
|
||||
private float nextScale() {
|
||||
// if( Config.get().GENERAL.RANDOM_SCALING > 0.0F ) { TODO configs
|
||||
// return baseScale * (1.0F + (theEntity.getRNG().nextFloat() - 0.5F) * Config.get().GENERAL.RANDOM_SCALING);
|
||||
// }
|
||||
return baseScale;
|
||||
// Don't do random on client side stuff
|
||||
if( theEntity.level == null || theEntity.level.isClientSide() ) return getBaseScale();
|
||||
|
||||
// Prioritize most specific value available
|
||||
final MobFamily.Species<? extends T> species = theEntity.getSpecies();
|
||||
final double randomScaling;
|
||||
if( species.config.GENERAL.randomScaling.get() >= 0.0 )
|
||||
randomScaling = species.config.GENERAL.randomScaling.get();
|
||||
else if( species.family.config.GENERAL.familyRandomScaling.get() >= 0.0 )
|
||||
randomScaling = species.family.config.GENERAL.familyRandomScaling.get();
|
||||
else
|
||||
randomScaling = Config.MAIN.GENERAL.masterRandomScaling.get();
|
||||
|
||||
return randomScaling <= 0.0 ? getBaseScale() :
|
||||
getBaseScale() * (1.0F + (theEntity.getRandom().nextFloat() - 0.5F) * 2.0F * (float) randomScaling);
|
||||
}
|
||||
|
||||
public void setRegenerationTime( int ticks ) { healTimeMax = ticks; }
|
||||
private void setRegenerationTime( int ticks ) { healTimeMax = ticks; }
|
||||
|
||||
public float getFallDamageMultiplier() { return fallDamageMultiplier; }
|
||||
|
||||
public void setFallDamageMultiplier( float value ) { fallDamageMultiplier = value; }
|
||||
private void setFallDamageMultiplier( float value ) { fallDamageMultiplier = value; }
|
||||
|
||||
public boolean isImmuneToFire() { return isImmuneToFire; }
|
||||
|
||||
public void setImmuneToFire( boolean value ) {
|
||||
private void setImmuneToFire( boolean value ) {
|
||||
isImmuneToFire = value;
|
||||
if( value ) {
|
||||
theEntity.setPathfindingMalus( PathNodeType.LAVA, PathNodeType.WATER.getMalus() );
|
||||
|
@ -326,7 +328,7 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
|
||||
public boolean isImmuneToBurning() { return isImmuneToBurning; }
|
||||
|
||||
public void setImmuneToBurning( boolean value ) {
|
||||
private void setImmuneToBurning( boolean value ) {
|
||||
theEntity.clearFire();
|
||||
isImmuneToBurning = value;
|
||||
if( value ) {
|
||||
|
@ -341,23 +343,23 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
|
||||
public boolean allowLeashing() { return allowLeashing; }
|
||||
|
||||
public void setAllowLeashing( boolean value ) { allowLeashing = value; }
|
||||
private void setAllowLeashing( boolean value ) { allowLeashing = value; }
|
||||
|
||||
public boolean ignorePressurePlates() { return ignorePressurePlates; }
|
||||
|
||||
public void setIgnorePressurePlates( boolean value ) { ignorePressurePlates = value; }
|
||||
private void setIgnorePressurePlates( boolean value ) { ignorePressurePlates = value; }
|
||||
|
||||
public boolean canBreatheInWater() { return canBreatheInWater; }
|
||||
|
||||
public void setCanBreatheInWater( boolean value ) { canBreatheInWater = value; }
|
||||
private void setCanBreatheInWater( boolean value ) { canBreatheInWater = value; }
|
||||
|
||||
public boolean ignoreWaterPush() { return ignoreWaterPush; }
|
||||
|
||||
public void setIgnoreWaterPush( boolean value ) { ignoreWaterPush = value; }
|
||||
private void setIgnoreWaterPush( boolean value ) { ignoreWaterPush = value; }
|
||||
|
||||
public boolean isDamagedByWater() { return isDamagedByWater; }
|
||||
|
||||
public void setDamagedByWater( boolean value ) {
|
||||
private void setDamagedByWater( boolean value ) {
|
||||
isDamagedByWater = value;
|
||||
theEntity.setPathfindingMalus( PathNodeType.WATER, value ? PathNodeType.LAVA.getMalus() : PathNodeType.WATER.getMalus() );
|
||||
}
|
||||
|
@ -368,12 +370,10 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
* @param block The block state to test.
|
||||
* @return True if the block is allowed to apply its stuck speed multiplier.
|
||||
*/
|
||||
public boolean canBeStuckIn( BlockState block ) { return !immuneToStickyBlocks.contains( block.getBlock().getDescriptionId() ); }
|
||||
public boolean canBeStuckIn( BlockState block ) { return !immuneToStickyBlocks.contains( block.getBlock() ); }
|
||||
|
||||
/** @param blocks The sticky block(s) to grant immunity from. */
|
||||
public void addStickyBlockImmunity( Block... blocks ) {
|
||||
for( Block block : blocks ) immuneToStickyBlocks.add( block.getDescriptionId() );
|
||||
}
|
||||
private void addStickyBlockImmunity( Collection<Block> blocks ) { immuneToStickyBlocks.addAll( blocks ); }
|
||||
|
||||
/**
|
||||
* Tests a potion effect to see if it is applicable to the entity.
|
||||
|
@ -387,14 +387,38 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
switch( event.getResult() ) {
|
||||
case DENY: return false;
|
||||
case ALLOW: return true;
|
||||
default: return !immuneToPotions.contains( effect.getDescriptionId() );
|
||||
default: return !immuneToPotions.contains( effect.getEffect() );
|
||||
}
|
||||
}
|
||||
|
||||
/** @param effects The effect(s) to grant immunity from. */
|
||||
public void addPotionImmunity( Effect... effects ) {
|
||||
for( Effect effect : effects ) immuneToPotions.add( effect.getDescriptionId() );
|
||||
}
|
||||
private void addPotionImmunity( Collection<Effect> effects ) { immuneToPotions.addAll( effects ); }
|
||||
|
||||
public float getRangedAttackDamage() { return rangedAttackDamage; }
|
||||
|
||||
public void setRangedAttackDamage( float value ) { rangedAttackDamage = value; }
|
||||
|
||||
public float getRangedAttackSpread() { return rangedAttackSpread; }
|
||||
|
||||
public void setRangedAttackSpread( float value ) { rangedAttackSpread = value; }
|
||||
|
||||
public float getRangedWalkSpeed() { return rangedWalkSpeed; }
|
||||
|
||||
public void setRangedWalkSpeed( float value ) { rangedWalkSpeed = value; }
|
||||
|
||||
public int getRangedAttackCooldown() { return rangedAttackCooldown; }
|
||||
|
||||
public void setRangedAttackCooldown( int value ) { rangedAttackCooldown = value; }
|
||||
|
||||
public int getRangedAttackMaxCooldown() { return rangedAttackMaxCooldown; }
|
||||
|
||||
public void setRangedAttackMaxCooldown( int value ) { rangedAttackMaxCooldown = value; }
|
||||
|
||||
public float getRangedAttackMaxRange() { return rangedAttackMaxRange; }
|
||||
|
||||
public void setRangedAttackMaxRange( float value ) { rangedAttackMaxRange = value; }
|
||||
|
||||
public void disableRangedAttack() { setRangedAttackMaxRange( 0.0F ); }
|
||||
|
||||
/**
|
||||
* Saves this data to NBT.
|
||||
|
@ -403,22 +427,14 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
*/
|
||||
public void writeToNBT( CompoundNBT tag ) {
|
||||
tag.putFloat( TAG_RENDER_SCALE, getRenderScale() );
|
||||
tag.putInt( TAG_EXPERIENCE, theEntity.getExperience() );
|
||||
tag.putByte( TAG_REGENERATION, (byte) healTimeMax );
|
||||
|
||||
tag.putString( TAG_TEXTURE, texture.toString() );
|
||||
tag.putString( TAG_TEXTURE_EYES, textureEyes == null ? "" : textureEyes.toString() );
|
||||
tag.putString( TAG_TEXTURE_OVER, textureOverlay == null ? "" : textureOverlay.toString() );
|
||||
|
||||
// Arrow AI
|
||||
tag.putFloat( TAG_ARROW_DAMAGE, rangedAttackDamage );
|
||||
tag.putFloat( TAG_ARROW_SPREAD, rangedAttackSpread );
|
||||
tag.putFloat( TAG_ARROW_WALK_SPEED, rangedWalkSpeed );
|
||||
tag.putShort( TAG_ARROW_REFIRE_MIN, (short) rangedAttackCooldown );
|
||||
tag.putShort( TAG_ARROW_REFIRE_MAX, (short) rangedAttackMaxCooldown );
|
||||
tag.putFloat( TAG_ARROW_RANGE, rangedAttackMaxRange );
|
||||
|
||||
// Abilities
|
||||
// Capabilities
|
||||
tag.putInt( TAG_EXPERIENCE, theEntity.getExperience() );
|
||||
tag.putByte( TAG_REGENERATION, (byte) healTimeMax );
|
||||
tag.putFloat( TAG_FALL_MULTI, getFallDamageMultiplier() );
|
||||
tag.putBoolean( TAG_FIRE_IMMUNE, isImmuneToFire() );
|
||||
tag.putBoolean( TAG_BURN_IMMUNE, isImmuneToBurning() );
|
||||
|
@ -429,16 +445,32 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
tag.putBoolean( TAG_WATER_DAMAGE, isDamagedByWater() );
|
||||
|
||||
final ListNBT stickyBlocksTag = new ListNBT();
|
||||
for( String blockName : immuneToStickyBlocks ) {
|
||||
stickyBlocksTag.add( StringNBT.valueOf( blockName ) );
|
||||
for( Block block : immuneToStickyBlocks ) {
|
||||
final ResourceLocation regKey = ForgeRegistries.BLOCKS.getKey( block );
|
||||
if( regKey != null ) stickyBlocksTag.add( StringNBT.valueOf( SpecialMobs.toString( regKey ) ) );
|
||||
}
|
||||
tag.put( TAG_STICKY_IMMUNE, stickyBlocksTag );
|
||||
|
||||
final ListNBT potionsTag = new ListNBT();
|
||||
for( String potionName : immuneToPotions ) {
|
||||
potionsTag.add( StringNBT.valueOf( potionName ) );
|
||||
for( Effect effect : immuneToPotions ) {
|
||||
final ResourceLocation regKey = ForgeRegistries.POTIONS.getKey( effect );
|
||||
if( regKey != null ) potionsTag.add( StringNBT.valueOf( SpecialMobs.toString( regKey ) ) );
|
||||
}
|
||||
tag.put( TAG_POTION_IMMUNE, potionsTag );
|
||||
|
||||
// Ranged attack stats (optional)
|
||||
if( getRangedAttackDamage() >= 0.0F )
|
||||
tag.putFloat( TAG_ARROW_DAMAGE, getRangedAttackDamage() );
|
||||
if( getRangedAttackSpread() >= 0.0F )
|
||||
tag.putFloat( TAG_ARROW_SPREAD, getRangedAttackSpread() );
|
||||
if( getRangedWalkSpeed() >= 0.0F )
|
||||
tag.putFloat( TAG_ARROW_WALK_SPEED, getRangedWalkSpeed() );
|
||||
if( getRangedAttackCooldown() >= 0 )
|
||||
tag.putShort( TAG_ARROW_REFIRE_MIN, (short) getRangedAttackCooldown() );
|
||||
if( getRangedAttackMaxCooldown() >= 0 )
|
||||
tag.putShort( TAG_ARROW_REFIRE_MAX, (short) getRangedAttackMaxCooldown() );
|
||||
if( getRangedAttackMaxRange() >= 0.0F )
|
||||
tag.putFloat( TAG_ARROW_RANGE, getRangedAttackMaxRange() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -450,12 +482,6 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
if( tag.contains( TAG_RENDER_SCALE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRenderScale( tag.getFloat( TAG_RENDER_SCALE ) );
|
||||
}
|
||||
if( tag.contains( TAG_EXPERIENCE, NBT_TYPE_NUMERICAL ) ) {
|
||||
theEntity.setExperience( tag.getInt( TAG_EXPERIENCE ) );
|
||||
}
|
||||
if( tag.contains( TAG_REGENERATION, NBT_TYPE_NUMERICAL ) ) {
|
||||
healTimeMax = tag.getByte( TAG_REGENERATION );
|
||||
}
|
||||
|
||||
try {
|
||||
if( tag.contains( TAG_TEXTURE, NBT_TYPE_STRING ) ) {
|
||||
|
@ -472,27 +498,13 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
SpecialMobs.LOG.warn( "Failed to load textures from NBT! " + theEntity.toString() );
|
||||
}
|
||||
|
||||
// Arrow AI
|
||||
if( tag.contains( TAG_ARROW_DAMAGE, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedAttackDamage = tag.getFloat( TAG_ARROW_DAMAGE );
|
||||
// Capabilities
|
||||
if( tag.contains( TAG_EXPERIENCE, NBT_TYPE_NUMERICAL ) ) {
|
||||
theEntity.setExperience( tag.getInt( TAG_EXPERIENCE ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_SPREAD, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedAttackSpread = tag.getFloat( TAG_ARROW_SPREAD );
|
||||
if( tag.contains( TAG_REGENERATION, NBT_TYPE_NUMERICAL ) ) {
|
||||
healTimeMax = tag.getByte( TAG_REGENERATION );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_WALK_SPEED, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedWalkSpeed = tag.getFloat( TAG_ARROW_WALK_SPEED );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_REFIRE_MIN, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedAttackCooldown = tag.getShort( TAG_ARROW_REFIRE_MIN );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_REFIRE_MAX, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedAttackMaxCooldown = tag.getShort( TAG_ARROW_REFIRE_MAX );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_RANGE, NBT_TYPE_NUMERICAL ) ) {
|
||||
rangedAttackMaxRange = tag.getFloat( TAG_ARROW_RANGE );
|
||||
}
|
||||
|
||||
// Abilities
|
||||
if( tag.contains( TAG_FALL_MULTI, NBT_TYPE_NUMERICAL ) ) {
|
||||
setFallDamageMultiplier( tag.getFloat( TAG_FALL_MULTI ) );
|
||||
}
|
||||
|
@ -502,12 +514,6 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
if( tag.contains( TAG_BURN_IMMUNE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setImmuneToBurning( tag.getBoolean( TAG_BURN_IMMUNE ) );
|
||||
}
|
||||
if( tag.contains( TAG_LEASHABLE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setAllowLeashing( tag.getBoolean( TAG_LEASHABLE ) );
|
||||
}
|
||||
if( tag.contains( TAG_TRAP_IMMUNE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setIgnorePressurePlates( tag.getBoolean( TAG_TRAP_IMMUNE ) );
|
||||
}
|
||||
if( tag.contains( TAG_DROWN_IMMUNE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setCanBreatheInWater( tag.getBoolean( TAG_DROWN_IMMUNE ) );
|
||||
}
|
||||
|
@ -517,19 +523,49 @@ public class SpecialMobData<T extends LivingEntity & ISpecialMob<T>> {
|
|||
if( tag.contains( TAG_WATER_DAMAGE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setDamagedByWater( tag.getBoolean( TAG_WATER_DAMAGE ) );
|
||||
}
|
||||
if( tag.contains( TAG_LEASHABLE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setAllowLeashing( tag.getBoolean( TAG_LEASHABLE ) );
|
||||
}
|
||||
if( tag.contains( TAG_TRAP_IMMUNE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setIgnorePressurePlates( tag.getBoolean( TAG_TRAP_IMMUNE ) );
|
||||
}
|
||||
if( tag.contains( TAG_STICKY_IMMUNE, NBT_TYPE_LIST ) ) {
|
||||
final ListNBT stickyBlocksTag = tag.getList( TAG_STICKY_IMMUNE, NBT_TYPE_STRING );
|
||||
immuneToStickyBlocks.clear();
|
||||
for( int i = 0; i < stickyBlocksTag.size(); i++ ) {
|
||||
immuneToStickyBlocks.add( stickyBlocksTag.getString( i ) );
|
||||
final Block block = ForgeRegistries.BLOCKS.getValue( new ResourceLocation( stickyBlocksTag.getString( i ) ) );
|
||||
if( block != null && !block.is( Blocks.AIR ) )
|
||||
immuneToStickyBlocks.add( block );
|
||||
}
|
||||
}
|
||||
if( tag.contains( TAG_POTION_IMMUNE, NBT_TYPE_LIST ) ) {
|
||||
final ListNBT potionsTag = tag.getList( TAG_POTION_IMMUNE, NBT_TYPE_STRING );
|
||||
immuneToPotions.clear();
|
||||
for( int i = 0; i < potionsTag.size(); i++ ) {
|
||||
immuneToPotions.add( potionsTag.getString( i ) );
|
||||
final Effect effect = ForgeRegistries.POTIONS.getValue( new ResourceLocation( potionsTag.getString( i ) ) );
|
||||
if( effect != null )
|
||||
immuneToPotions.add( effect );
|
||||
}
|
||||
}
|
||||
|
||||
// Ranged attack stats
|
||||
if( tag.contains( TAG_ARROW_DAMAGE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedAttackDamage( tag.getFloat( TAG_ARROW_DAMAGE ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_SPREAD, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedAttackSpread( tag.getFloat( TAG_ARROW_SPREAD ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_WALK_SPEED, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedWalkSpeed( tag.getFloat( TAG_ARROW_WALK_SPEED ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_REFIRE_MIN, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedAttackCooldown( tag.getShort( TAG_ARROW_REFIRE_MIN ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_REFIRE_MAX, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedAttackMaxCooldown( tag.getShort( TAG_ARROW_REFIRE_MAX ) );
|
||||
}
|
||||
if( tag.contains( TAG_ARROW_RANGE, NBT_TYPE_NUMERICAL ) ) {
|
||||
setRangedAttackMaxRange( tag.getFloat( TAG_ARROW_RANGE ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package fathertoast.specialmobs.common.entity.ai;
|
||||
|
||||
public interface IExplodingMob {
|
||||
/** Sets this exploding entity's swell direction. */
|
||||
void setSwellDir( int value );
|
||||
|
||||
/** @return This exploding entity's swell direction. */
|
||||
int getSwellDir();
|
||||
|
||||
/** @return Additional range from its target at which this entity will start to explode. */
|
||||
default double getExtraRange() { return 0.0; }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package fathertoast.specialmobs.common.entity.ai.goal;
|
||||
|
||||
import fathertoast.specialmobs.common.entity.creeper._SpecialCreeperEntity;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.entity.zombie.MadScientistZombieEntity;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.monster.CreeperEntity;
|
||||
|
@ -85,12 +85,7 @@ public class ChargeCreeperGoal<T extends MadScientistZombieEntity> extends Goal
|
|||
madman.getLookControl().setLookAt( this.creeper.getX(), this.creeper.getEyeY(), this.creeper.getZ() );
|
||||
|
||||
if( madman.distanceTo( creeper ) < 1.5D ) {
|
||||
creeper.getEntityData().set( CreeperEntity.DATA_IS_POWERED, true );
|
||||
|
||||
// HEE HEE HEE HAW
|
||||
if( creeper instanceof _SpecialCreeperEntity && creeper.level.random.nextDouble() < 0.1 ) { // TODO config
|
||||
((_SpecialCreeperEntity) creeper).setSupercharged( true );
|
||||
}
|
||||
MobHelper.charge( creeper );
|
||||
madman.level.playSound( null, creeper.getX() + 0.5D, creeper.getY(), creeper.getZ() + 0.5D, SoundEvents.BEE_STING, SoundCategory.HOSTILE, 0.9F, 1.0F );
|
||||
creeper = null;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class SpecialBlazeAttackGoal extends Goal {
|
|||
else lastSeen++;
|
||||
|
||||
final double distanceSqr = blaze.distanceToSqr( target );
|
||||
final float rangeSq = data.rangedAttackMaxRange * data.rangedAttackMaxRange;
|
||||
final float rangeSq = data.getRangedAttackMaxRange() * data.getRangedAttackMaxRange();
|
||||
if( distanceSqr < getAttackReachSqr( target ) ) {
|
||||
if( canSee && attackTime <= 0 ) {
|
||||
attackTime = 20;
|
||||
|
@ -71,14 +71,14 @@ public class SpecialBlazeAttackGoal extends Goal {
|
|||
attackStep++;
|
||||
|
||||
if( attackStep == 1 ) {
|
||||
attackTime = data.rangedAttackMaxCooldown - data.rangedAttackCooldown;
|
||||
attackTime = data.getRangedAttackCooldown();
|
||||
blaze.setCharged( true );
|
||||
}
|
||||
else if( attackStep <= 1 + blaze.fireballBurstCount ) {
|
||||
attackTime = blaze.fireballBurstDelay;
|
||||
}
|
||||
else {
|
||||
attackTime = data.rangedAttackCooldown;
|
||||
attackTime = data.getRangedAttackMaxCooldown() - data.getRangedAttackCooldown();
|
||||
attackStep = 0;
|
||||
blaze.setCharged( false );
|
||||
}
|
||||
|
|
|
@ -38,19 +38,19 @@ public class SpecialGhastFireballAttackGoal extends Goal {
|
|||
|
||||
final SpecialMobData<_SpecialGhastEntity> data = ghast.getSpecialData();
|
||||
|
||||
if( target.distanceToSqr( ghast ) < data.rangedAttackMaxRange * data.rangedAttackMaxRange && ghast.canSee( target ) ) {
|
||||
if( target.distanceToSqr( ghast ) < data.getRangedAttackMaxRange() * data.getRangedAttackMaxRange() && ghast.canSee( target ) ) {
|
||||
chargeTime++;
|
||||
if( chargeTime == (data.rangedAttackCooldown >> 1) && !ghast.isSilent() ) {
|
||||
if( chargeTime == (data.getRangedAttackCooldown() >> 1) && !ghast.isSilent() ) {
|
||||
ghast.level.levelEvent( null, References.EVENT_GHAST_WARN, ghast.blockPosition(), 0 );
|
||||
}
|
||||
if( chargeTime >= data.rangedAttackCooldown ) {
|
||||
if( chargeTime >= data.getRangedAttackCooldown() ) {
|
||||
ghast.performRangedAttack( target, 1.0F );
|
||||
chargeTime = data.rangedAttackCooldown - data.rangedAttackMaxCooldown;
|
||||
chargeTime = data.getRangedAttackCooldown() - data.getRangedAttackMaxCooldown();
|
||||
}
|
||||
}
|
||||
else if( chargeTime > 0 ) {
|
||||
chargeTime--;
|
||||
}
|
||||
ghast.setCharging( chargeTime > (data.rangedAttackCooldown >> 1) );
|
||||
ghast.setCharging( chargeTime > (data.getRangedAttackCooldown() >> 1) );
|
||||
}
|
||||
}
|
|
@ -28,8 +28,8 @@ public class SpecialGhastLookAroundGoal extends Goal {
|
|||
public void tick() {
|
||||
final LivingEntity target = ghast.getTarget();
|
||||
if( target != null ) {
|
||||
final float range = ghast.getSpecialData().rangedAttackMaxRange > 0.0F ?
|
||||
ghast.getSpecialData().rangedAttackMaxRange :
|
||||
final float range = ghast.getSpecialData().getRangedAttackMaxRange() > 0.0F ?
|
||||
ghast.getSpecialData().getRangedAttackMaxRange() :
|
||||
16.0F; // Range for melee ghast to face target
|
||||
|
||||
if( target.distanceToSqr( ghast ) < range * range ) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package fathertoast.specialmobs.common.entity.ai.goal;
|
||||
|
||||
import fathertoast.specialmobs.common.entity.ai.IExplodingMob;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.MobEntity;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* The "creeper swell" goal repurposed for use on other mobs.
|
||||
* <p>
|
||||
* {@link net.minecraft.entity.ai.goal.CreeperSwellGoal}
|
||||
*/
|
||||
public class SpecialSwellGoal<T extends MobEntity & IExplodingMob> extends Goal {
|
||||
|
||||
private final T mob;
|
||||
|
||||
private LivingEntity target;
|
||||
|
||||
public SpecialSwellGoal( T entity ) {
|
||||
mob = entity;
|
||||
setFlags( EnumSet.of( Flag.MOVE ) );
|
||||
}
|
||||
|
||||
public boolean canUse() {
|
||||
final LivingEntity target = mob.getTarget();
|
||||
return mob.getSwellDir() > 0 || target != null && mob.distanceToSqr( target ) < 9.0F + mob.getExtraRange();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mob.getNavigation().stop();
|
||||
target = mob.getTarget();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
mob.setSwellDir( -1 );
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
if( target == null || mob.distanceToSqr( target ) > 49.0 || !mob.getSensing().canSee( target ) ) {
|
||||
mob.setSwellDir( -1 );
|
||||
}
|
||||
else {
|
||||
mob.setSwellDir( 1 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,14 +3,11 @@ package fathertoast.specialmobs.common.entity.blaze;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -28,17 +25,12 @@ public class CinderBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<CinderBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.5F, 0.9F );
|
||||
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.DISABLED );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, -2.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFC0CB ).weight( BestiaryInfo.DefaultWeight.DISABLED )
|
||||
.size( 0.5F, 0.5F, 0.9F )
|
||||
.experience( 2 ).disableRangedAttack()
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, -2.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -55,23 +47,18 @@ public class CinderBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<CinderBlazeEntity> getVariantFactory() { return CinderBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends CinderBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public CinderBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.5F );
|
||||
xpReward = 1;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage -= 1.0F;
|
||||
disableRangedAI();
|
||||
}
|
||||
public CinderBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
target.setSecondsOnFire( 4 );
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import net.minecraft.nbt.CompoundNBT;
|
|||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.potion.Potions;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -37,9 +37,11 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<ConflagrationBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.7F );
|
||||
return new BestiaryInfo( 0xFFF87E, BestiaryInfo.BaseWeight.LOW );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFF87E ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureBaseOnly()
|
||||
.size( 1.5F, 0.9F, 2.7F )
|
||||
.addExperience( 4 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -58,6 +60,11 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<ConflagrationBlazeEntity> getVariantFactory() { return ConflagrationBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends ConflagrationBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
|
@ -68,13 +75,10 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
/** The level of increased attack damage gained. */
|
||||
private int growthLevel;
|
||||
|
||||
public ConflagrationBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
xpReward += 4;
|
||||
}
|
||||
public ConflagrationBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** 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.stealLife( this, (LivingEntity) target, 2.0F );
|
||||
|
@ -91,12 +95,6 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
|
||||
if( !level.isClientSide() && growthLevel < 7 ) {
|
||||
growthLevel++;
|
||||
|
||||
getSpecialData().rangedAttackDamage += 0.5F;
|
||||
getSpecialData().rangedAttackCooldown -= 4;
|
||||
getSpecialData().rangedAttackMaxCooldown -= 4;
|
||||
if( growthLevel == 7 ) fireballBurstCount++;
|
||||
|
||||
updateFeedingLevels();
|
||||
}
|
||||
amount /= 2.0F;
|
||||
|
@ -107,6 +105,13 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
/** Recalculates the modifiers associated with this entity's feeding level counters. */
|
||||
private void updateFeedingLevels() {
|
||||
if( level != null && !level.isClientSide ) {
|
||||
final int cooldownReduction = MathHelper.floor( getConfig().GENERAL.rangedAttackCooldown.get() * growthLevel * 0.1 );
|
||||
getSpecialData().setRangedAttackCooldown( getConfig().GENERAL.rangedAttackCooldown.get() - cooldownReduction );
|
||||
getSpecialData().setRangedAttackMaxCooldown( getConfig().GENERAL.rangedAttackMaxCooldown.get() - cooldownReduction );
|
||||
|
||||
fireballBurstCount = getConfig().BLAZES.fireballBurstCount.get();
|
||||
if( growthLevel >= 7 ) fireballBurstCount++;
|
||||
|
||||
final ModifiableAttributeInstance damage = getAttribute( Attributes.ATTACK_DAMAGE );
|
||||
//noinspection ConstantConditions
|
||||
damage.removeModifier( DAMAGE_BOOST.getId() );
|
||||
|
@ -130,12 +135,4 @@ public class ConflagrationBlazeEntity extends _SpecialBlazeEntity {
|
|||
growthLevel = saveTag.getByte( References.TAG_GROWTH_LEVEL );
|
||||
updateFeedingLevels();
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "conflagration" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -4,17 +4,14 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -30,17 +27,12 @@ public class EmberBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<EmberBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x000000 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.addAttribute( Attributes.ARMOR, 10.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x000000 )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 ).disableRangedAttack()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 ).addToAttribute( Attributes.ARMOR, 10.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -58,32 +50,21 @@ public class EmberBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<EmberBlazeEntity> getVariantFactory() { return EmberBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends EmberBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public EmberBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
disableRangedAI();
|
||||
}
|
||||
public EmberBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** 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 );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "ember" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,18 +3,17 @@ package fathertoast.specialmobs.common.entity.blaze;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.BlazeSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.entity.projectile.FireballEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -31,16 +30,18 @@ public class HellfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<HellfireBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.7F, 1.99F );
|
||||
return new BestiaryInfo( 0xDDDDDD );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xDDDDDD )
|
||||
.uniqueTextureBaseOnly()
|
||||
.size( 1.1F, 0.7F, 1.99F )
|
||||
.addExperience( 2 )
|
||||
.fireballAttack( 0.05, 60, 100, 40.0 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new BlazeSpeciesConfig( species, 1, 0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -58,31 +59,25 @@ public class HellfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<HellfireBlazeEntity> getVariantFactory() { return HellfireBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends HellfireBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
/** The base explosion strength of this blaze's fireballs. */
|
||||
private int explosionPower = 2;
|
||||
|
||||
public HellfireBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.1F );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackSpread *= 0.05F;
|
||||
setRangedAI( 1, 0, 60, 100, 40.0F );
|
||||
}
|
||||
public HellfireBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
@Override
|
||||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
if( !isSilent() ) level.levelEvent( null, References.EVENT_BLAZE_SHOOT, blockPosition(), 0 );
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().rangedAttackSpread;
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().getRangedAttackSpread();
|
||||
final double dX = target.getX() - getX() + getRandom().nextGaussian() * accelVariance;
|
||||
final double dY = target.getY( 0.5 ) - getY( 0.5 );
|
||||
final double dZ = target.getZ() - getZ() + getRandom().nextGaussian() * accelVariance;
|
||||
|
@ -105,12 +100,4 @@ public class HellfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
if( saveTag.contains( References.TAG_EXPLOSION_POWER, References.NBT_TYPE_NUMERICAL ) )
|
||||
explosionPower = saveTag.getByte( References.TAG_EXPLOSION_POWER );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "hellfire" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,18 +3,17 @@ package fathertoast.specialmobs.common.entity.blaze;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.config.species.BlazeSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -30,15 +29,17 @@ public class InfernoBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<InfernoBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xF14F00 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xF14F00 )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 )
|
||||
.fireballAttack( 3.0, 80, 100, 20.0 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new BlazeSpeciesConfig( species, 12, 2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -57,33 +58,21 @@ public class InfernoBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<InfernoBlazeEntity> getVariantFactory() { return InfernoBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends InfernoBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public InfernoBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackSpread *= 3.0F;
|
||||
setRangedAI( 12, 2, 80, 100, 20.0F );
|
||||
}
|
||||
public InfernoBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** 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 );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "inferno" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -4,7 +4,6 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
|
@ -13,7 +12,6 @@ import net.minecraft.block.BlockState;
|
|||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.entity.effect.LightningBoltEntity;
|
||||
import net.minecraft.item.Items;
|
||||
|
@ -21,7 +19,6 @@ import net.minecraft.tags.FluidTags;
|
|||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.IndirectEntityDamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -42,17 +39,12 @@ public class JoltBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<JoltBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x499CAE );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.addAttribute( Attributes.ARMOR, 10.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x499CAE )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 ).disableRangedAttack()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 ).addToAttribute( Attributes.ARMOR, 10.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -70,21 +62,18 @@ public class JoltBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<JoltBlazeEntity> getVariantFactory() { return JoltBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends JoltBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public JoltBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
disableRangedAI();
|
||||
}
|
||||
public JoltBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** 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 );
|
||||
|
@ -129,6 +118,10 @@ public class JoltBlazeEntity extends _SpecialBlazeEntity {
|
|||
return success;
|
||||
}
|
||||
|
||||
/** Called when this entity is struck by lightning. */
|
||||
@Override
|
||||
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { }
|
||||
|
||||
/** @return Teleports this "enderman" to a random nearby position; returns true if successful. */
|
||||
protected boolean teleport() {
|
||||
if( level.isClientSide() || !isAlive() ) return false;
|
||||
|
@ -174,16 +167,4 @@ public class JoltBlazeEntity extends _SpecialBlazeEntity {
|
|||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/** Called when this entity is struck by lightning. */
|
||||
@Override
|
||||
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) { }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "jolt" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,16 +3,15 @@ package fathertoast.specialmobs.common.entity.blaze;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.WildfireBlazeSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -30,16 +29,19 @@ public class WildfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
public static MobFamily.Species<WildfireBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.7F );
|
||||
return new BestiaryInfo( 0xF4EE32 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xF4EE32 )
|
||||
.uniqueTextureBaseOnly()
|
||||
.size( 1.5F, 0.9F, 2.7F )
|
||||
.addExperience( 2 ).regen( 40 )
|
||||
.fireballAttack( 0.1, 30, 50, 20.0 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialBlazeEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new WildfireBlazeSpeciesConfig( species, 1, 0,
|
||||
3, 6, 4, 10 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -58,6 +60,11 @@ public class WildfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<WildfireBlazeEntity> getVariantFactory() { return WildfireBlazeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends WildfireBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
|
@ -68,22 +75,16 @@ public class WildfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
|
||||
public WildfireBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
getSpecialData().setRegenerationTime( 40 );
|
||||
xpReward += 2;
|
||||
|
||||
babies = 3 + random.nextInt( 4 );
|
||||
summons = 4 + random.nextInt( 7 );
|
||||
babies = getConfig().WILDFIRE.babies.next( random );
|
||||
summons = getConfig().WILDFIRE.summons.next( random );
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
/** @return This entity's species config. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackSpread *= 0.1F;
|
||||
setRangedAI( 1, 0, 30, 50, 20.0F );
|
||||
}
|
||||
public WildfireBlazeSpeciesConfig getConfig() { return (WildfireBlazeSpeciesConfig) getSpecies().config; }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
target.setSecondsOnFire( 8 );
|
||||
}
|
||||
|
@ -157,12 +158,4 @@ public class WildfireBlazeEntity extends _SpecialBlazeEntity {
|
|||
if( saveTag.contains( References.TAG_SUMMONS, References.NBT_TYPE_NUMERICAL ) )
|
||||
summons = saveTag.getByte( References.TAG_SUMMONS );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "wildfire" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,8 @@ package fathertoast.specialmobs.common.entity.blaze;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.config.species.BlazeSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
|
@ -25,14 +26,10 @@ import net.minecraft.network.datasync.DataSerializers;
|
|||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
|
@ -46,15 +43,24 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
public static MobFamily.Species<_SpecialBlazeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xFFF87E );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFF87E )
|
||||
.vanillaTextureBaseOnly( "textures/entity/blaze.png" )
|
||||
.experience( 10 ).fireImmune().waterSensitive()
|
||||
.fireballAttack( 1.0, 60, 100, 48.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return BlazeEntity.createAttributes();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new BlazeSpeciesConfig( species, 3, 6 );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
public BlazeSpeciesConfig getConfig() { return (BlazeSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() { return BlazeEntity.createAttributes(); }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Blaze",
|
||||
|
@ -72,12 +78,6 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
}
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
|
@ -86,29 +86,12 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
goalSelector.addGoal( 4, new SpecialBlazeAttackGoal( this ) );
|
||||
AIHelper.replaceHurtByTarget( this, new SpecialHurtByTargetGoal( this, BlazeEntity.class ).setAlertOthers() );
|
||||
|
||||
getSpecialData().rangedAttackDamage = 2.0F;
|
||||
setRangedAI( 3, 6, 60, 100, 48.0F );
|
||||
registerVariantGoals();
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void disableRangedAI() {
|
||||
setRangedAI( 0, 6, 60, 100, 0.0F );
|
||||
}
|
||||
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void setRangedAI( int burstCount, int burstDelay, int chargeTime, int cooldownTime, float range ) {
|
||||
fireballBurstCount = burstCount;
|
||||
fireballBurstDelay = burstDelay;
|
||||
|
||||
getSpecialData().rangedAttackCooldown = cooldownTime;
|
||||
getSpecialData().rangedAttackMaxCooldown = cooldownTime + chargeTime;
|
||||
getSpecialData().rangedAttackMaxRange = range;
|
||||
}
|
||||
|
||||
/** Called when this entity successfully damages a target to apply on-hit effects. */
|
||||
@Override
|
||||
public void doEnchantDamageEffects( LivingEntity attacker, Entity target ) {
|
||||
|
@ -119,6 +102,21 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
protected void onVariantAttack( Entity target ) { }
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
@Override
|
||||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
if( !isSilent() ) level.levelEvent( null, References.EVENT_BLAZE_SHOOT, blockPosition(), 0 );
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().getRangedAttackSpread();
|
||||
final double dX = target.getX() - getX() + getRandom().nextGaussian() * accelVariance;
|
||||
final double dY = target.getY( 0.5 ) - getY( 0.5 );
|
||||
final double dZ = target.getZ() - getZ() + getRandom().nextGaussian() * accelVariance;
|
||||
|
||||
final SmallFireballEntity fireball = new SmallFireballEntity( level, this, dX, dY, dZ );
|
||||
fireball.setPos( getX(), getY( 0.5 ) + 0.5, getZ() );
|
||||
level.addFreshEntity( fireball );
|
||||
}
|
||||
|
||||
/** Override to save data to this entity's NBT data. */
|
||||
public void addVariantSaveData( CompoundNBT saveTag ) { }
|
||||
|
||||
|
@ -136,35 +134,19 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
/** The ticks between each shot in a burst. */
|
||||
public int fireballBurstDelay;
|
||||
|
||||
public _SpecialBlazeEntity( EntityType<? extends _SpecialBlazeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
fireballBurstCount = getConfig().BLAZES.fireballBurstCount.get();
|
||||
fireballBurstDelay = getConfig().BLAZES.fireballBurstDelay.get();
|
||||
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
|
||||
}
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
@Override
|
||||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
if( !isSilent() ) level.levelEvent( null, References.EVENT_BLAZE_SHOOT, blockPosition(), 0 );
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().rangedAttackSpread;
|
||||
final double dX = target.getX() - getX() + getRandom().nextGaussian() * accelVariance;
|
||||
final double dY = target.getY( 0.5 ) - getY( 0.5 );
|
||||
final double dZ = target.getZ() - getZ() + getRandom().nextGaussian() * accelVariance;
|
||||
|
||||
final SmallFireballEntity fireball = new SmallFireballEntity( level, this, dX, dY, dZ );
|
||||
fireball.setPos( getX(), getY( 0.5 ) + 0.5, getZ() );
|
||||
level.addFreshEntity( fireball );
|
||||
}
|
||||
|
||||
/** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
|
||||
@Nullable
|
||||
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
|
||||
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
|
||||
groupData = super.finalizeSpawn( world, difficulty, spawnReason, groupData, eggTag );
|
||||
// TODO ranged attack
|
||||
return groupData;
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,7 +156,12 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
|
||||
/** @return This mob's special data. */
|
||||
@Override
|
||||
public SpecialMobData<_SpecialBlazeEntity> getSpecialData() { return specialData; }
|
||||
public final SpecialMobData<_SpecialBlazeEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialBlazeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
|
@ -184,16 +171,6 @@ public class _SpecialBlazeEntity extends BlazeEntity implements IRangedAttackMob
|
|||
@Override
|
||||
public final void setExperience( int xp ) { xpReward = xp; }
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "blaze/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = { new ResourceLocation( "textures/entity/blaze.png" ) };
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package fathertoast.specialmobs.common.entity.cavespider;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -27,18 +24,13 @@ public class BabyCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
public static MobFamily.Species<BabyCaveSpiderEntity> SPECIES;
|
||||
|
||||
@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( _SpecialCaveSpiderEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MAX_HEALTH, 1.0 / 3.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, -1.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFC0CB ).weight( BestiaryInfo.DefaultWeight.DISABLED )
|
||||
.size( 0.4F, 0.6F, 0.4F )
|
||||
.experience( 1 ).disableRangedAttack()
|
||||
.multiplyAttribute( Attributes.MAX_HEALTH, 0.33 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, -1.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -55,21 +47,13 @@ public class BabyCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<BabyCaveSpiderEntity> getVariantFactory() { return BabyCaveSpiderEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends BabyCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public BabyCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.4F );
|
||||
getSpecialData().rangedAttackDamage -= 1.0F;
|
||||
getSpecialData().rangedAttackMaxRange = 0.0F;
|
||||
xpReward = 1;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage -= 1.0F;
|
||||
getSpecialData().rangedAttackMaxRange = 0.0F;
|
||||
}
|
||||
public BabyCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) { super( entityType, world ); }
|
||||
}
|
|
@ -4,16 +4,12 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.goal.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;
|
||||
|
@ -29,16 +25,11 @@ public class FlyingCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
public static MobFamily.Species<FlyingCaveSpiderEntity> SPECIES;
|
||||
|
||||
@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( _SpecialCaveSpiderEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x6388B2 ).theme( BestiaryInfo.Theme.MOUNTAIN )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 ).fallImmune().disableRangedAttack()
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -56,30 +47,20 @@ public class FlyingCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<FlyingCaveSpiderEntity> getVariantFactory() { return FlyingCaveSpiderEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends FlyingCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public FlyingCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setFallDamageMultiplier( 0.0F );
|
||||
xpReward += 2;
|
||||
}
|
||||
public FlyingCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackMaxRange = 0.0F;
|
||||
|
||||
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; }
|
||||
}
|
|
@ -3,20 +3,18 @@ package fathertoast.specialmobs.common.entity.cavespider;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.MotherSpiderSpeciesConfig;
|
||||
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;
|
||||
|
@ -35,20 +33,25 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
public static MobFamily.Species<MotherCaveSpiderEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 0.6F );
|
||||
return new BestiaryInfo( 0xB300B3 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xB300B3 )
|
||||
.uniqueTextureWithEyes()
|
||||
.size( 0.8F, 0.9F, 0.6F )
|
||||
.addExperience( 1 ).regen( 30 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 16.0 ).addToAttribute( Attributes.ARMOR, 6.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 3.0 ).addToRangedDamage( 1.5 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCaveSpiderEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 16.0 )
|
||||
.addAttribute( Attributes.ARMOR, 6.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 3.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new MotherSpiderSpeciesConfig( species, DEFAULT_SPIT_CHANCE,
|
||||
2, 4, 2, 4 );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
@Override
|
||||
public MotherSpiderSpeciesConfig getConfig() { return (MotherSpiderSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Mother Cave Spider",
|
||||
|
@ -64,28 +67,23 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<MotherCaveSpiderEntity> getVariantFactory() { return MotherCaveSpiderEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends MotherCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public MotherCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.8F );
|
||||
getSpecialData().setRegenerationTime( 30 );
|
||||
xpReward += 1;
|
||||
|
||||
babies = 2 + random.nextInt( 3 );
|
||||
extraBabies = 2 + random.nextInt( 3 );
|
||||
}
|
||||
|
||||
/** The number of babies spawned on death. */
|
||||
private int babies;
|
||||
/** The number of extra babies that can be spawned from hits. */
|
||||
private int extraBabies;
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 1.5F;
|
||||
public MotherCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
babies = getConfig().MOTHER.babies.next( random );
|
||||
extraBabies = getConfig().MOTHER.extraBabies.next( random );
|
||||
}
|
||||
|
||||
/** @return Attempts to damage this entity; returns true if the hit was successful. */
|
||||
|
@ -159,13 +157,4 @@ public class MotherCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
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; }
|
||||
}
|
|
@ -3,7 +3,8 @@ package fathertoast.specialmobs.common.entity.cavespider;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.WebSpiderSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
@ -11,12 +12,10 @@ 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;
|
||||
|
||||
|
@ -33,19 +32,24 @@ public class WebCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
public static MobFamily.Species<WebCaveSpiderEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xE7E7E7, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - forest
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xE7E7E7 ).weight( BestiaryInfo.DefaultWeight.LOW ).theme( BestiaryInfo.Theme.FOREST )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 )
|
||||
.spitAttackMultiplied( 0.1, 1.0, 2.0F, 1.0 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 4.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCaveSpiderEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 4.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new WebSpiderSpeciesConfig( species, 0.01, 2, 6 );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
@Override
|
||||
public WebSpiderSpeciesConfig getConfig() { return (WebSpiderSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Cave Weaver",
|
||||
|
@ -61,18 +65,22 @@ public class WebCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<WebCaveSpiderEntity> getVariantFactory() { return WebCaveSpiderEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends WebCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public WebCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
webCount = 2 + random.nextInt( 5 );
|
||||
}
|
||||
|
||||
/** The number of cobwebs this spider can place. */
|
||||
private int webCount;
|
||||
|
||||
public WebCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
webCount = getConfig().WEB.webCount.next( random );
|
||||
}
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
|
@ -113,13 +121,4 @@ public class WebCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
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; }
|
||||
}
|
|
@ -4,18 +4,15 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.EffectType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -31,16 +28,12 @@ public class WitchCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
public static MobFamily.Species<WitchCaveSpiderEntity> SPECIES;
|
||||
|
||||
@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( _SpecialCaveSpiderEntity.createAttributes() )
|
||||
.addAttribute( Attributes.ARMOR, 15.0 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xDD0E0E ).weight( BestiaryInfo.DefaultWeight.LOW ).theme( BestiaryInfo.Theme.FOREST )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 )
|
||||
.spitAttackMultiplied( 0.1, 1.0, 2.0F, 1.0 )
|
||||
.addToAttribute( Attributes.ARMOR, 15.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -58,13 +51,15 @@ public class WitchCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<WitchCaveSpiderEntity> getVariantFactory() { return WitchCaveSpiderEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends WitchCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public WitchCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
public WitchCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
|
@ -81,13 +76,4 @@ public class WitchCaveSpiderEntity extends _SpecialCaveSpiderEntity {
|
|||
// 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; }
|
||||
}
|
|
@ -3,7 +3,8 @@ package fathertoast.specialmobs.common.entity.cavespider;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpiderSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
|
@ -21,13 +22,9 @@ 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
|
||||
|
@ -41,15 +38,26 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
public static MobFamily.Species<_SpecialCaveSpiderEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xA80E0E );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xA80E0E ).familySize( 0.7F )
|
||||
.vanillaTextureWithEyes( "textures/entity/spider/cave_spider.png", "textures/entity/spider_eyes.png" )
|
||||
.experience( 5 ).spider()
|
||||
.spitAttack( 1.0, 1.3, 40, 40, 10.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return CaveSpiderEntity.createAttributes();
|
||||
protected static final double DEFAULT_SPIT_CHANCE = 0.05;
|
||||
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new SpiderSpeciesConfig( species, DEFAULT_SPIT_CHANCE );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
public SpiderSpeciesConfig getConfig() { return (SpiderSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() { return CaveSpiderEntity.createAttributes(); }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Cave Spider",
|
||||
|
@ -67,21 +75,10 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
super.registerGoals();
|
||||
|
||||
getSpecialData().rangedAttackDamage = 1.0F;
|
||||
getSpecialData().rangedAttackSpread = 1.3F;
|
||||
getSpecialData().rangedAttackCooldown = 40;
|
||||
getSpecialData().rangedAttackMaxCooldown = getSpecialData().rangedAttackCooldown;
|
||||
getSpecialData().rangedAttackMaxRange = 10.0F;
|
||||
registerVariantGoals();
|
||||
}
|
||||
|
||||
|
@ -110,20 +107,18 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
/** The parameter for special mob render scale. */
|
||||
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialCaveSpiderEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
public _SpecialCaveSpiderEntity( EntityType<? extends _SpecialCaveSpiderEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
if( !getConfig().SPIDERS.spitterChance.rollChance( random ) ) getSpecialData().disableRangedAttack();
|
||||
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 0.7F );
|
||||
}
|
||||
|
||||
/** 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;
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,7 +128,12 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
|
||||
/** @return This mob's special data. */
|
||||
@Override
|
||||
public SpecialMobData<_SpecialCaveSpiderEntity> getSpecialData() { return specialData; }
|
||||
public final SpecialMobData<_SpecialCaveSpiderEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialCaveSpiderEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
|
@ -143,19 +143,6 @@ public class _SpecialCaveSpiderEntity extends CaveSpiderEntity implements ISpeci
|
|||
@Override
|
||||
public final void setExperience( int xp ) { xpReward = xp; }
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "cavespider/" + type + ".png" );
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
|
|
@ -10,14 +10,12 @@ import mcp.MethodsReturnNonnullByDefault;
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.potion.Potions;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
@ -36,8 +34,10 @@ public class DarkCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<DarkCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xF9FF3A );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xF9FF3A )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 1 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -56,13 +56,15 @@ public class DarkCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<DarkCreeperEntity> getVariantFactory() { return DarkCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends DarkCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public DarkCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 1;
|
||||
}
|
||||
public DarkCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius / 2.0F ); }
|
||||
|
@ -121,13 +123,4 @@ public class DarkCreeperEntity extends _SpecialCreeperEntity {
|
|||
protected void modifyVariantLingeringCloudEffects( List<EffectInstance> potions ) {
|
||||
potions.add( new EffectInstance( Effects.BLINDNESS, 100 ) );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "dark" ),
|
||||
GET_TEXTURE_PATH( "dark_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,17 +3,15 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.CreeperSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.Blocks;
|
||||
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;
|
||||
|
@ -29,16 +27,17 @@ public class DeathCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<DeathCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.9F, 2.6F );
|
||||
return new BestiaryInfo( 0xCD0000 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xCD0000 )
|
||||
.uniqueTextureWithEyes()
|
||||
.size( 1.5F, 0.9F, 2.6F )
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new CreeperSpeciesConfig( species, false, true, false );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -57,25 +56,16 @@ public class DeathCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<DeathCreeperEntity> getVariantFactory() { return DeathCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends DeathCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public DeathCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
setExplodesWhileBurning( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
public DeathCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius + 1.0F ); }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "death" ),
|
||||
GET_TEXTURE_PATH( "death_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
|
@ -11,11 +10,8 @@ import mcp.MethodsReturnNonnullByDefault;
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
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.util.math.BlockPos;
|
||||
import net.minecraft.world.Explosion;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -33,15 +29,11 @@ public class DirtCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<DirtCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x78553B );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.ARMOR, 6.0 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x78553B )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 ).burnImmune()
|
||||
.addToAttribute( Attributes.ARMOR, 6.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -61,14 +53,15 @@ public class DirtCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<DirtCreeperEntity> getVariantFactory() { return DirtCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends DirtCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public DirtCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToBurning( true );
|
||||
xpReward += 1;
|
||||
}
|
||||
public DirtCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion. */
|
||||
@Override
|
||||
|
@ -97,12 +90,4 @@ public class DirtCreeperEntity extends _SpecialCreeperEntity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "dirt" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -9,10 +9,8 @@ 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.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -29,9 +27,10 @@ public class DoomCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<DoomCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x494949 );
|
||||
//TODO theme - forest
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x494949 ).theme( BestiaryInfo.Theme.FOREST )
|
||||
.uniqueTextureWithOverlay()
|
||||
.addExperience( 1 ).effectImmune( Effects.HARM, Effects.WITHER );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -49,14 +48,15 @@ public class DoomCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<DoomCreeperEntity> getVariantFactory() { return DoomCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends DoomCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public DoomCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().addPotionImmunity( Effects.HARM, Effects.WITHER );
|
||||
xpReward += 1;
|
||||
}
|
||||
public DoomCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius / 2.0F ); }
|
||||
|
@ -82,14 +82,4 @@ public class DoomCreeperEntity extends _SpecialCreeperEntity {
|
|||
protected void modifyVariantLingeringCloud( AreaEffectCloudEntity potionCloud ) {
|
||||
potionCloud.setRadius( (float) explosionRadius * (isPowered() ? 2.0F : 1.0F) );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "doom" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "doom_overlay" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootEntryItemBuilder;
|
||||
|
@ -13,14 +12,11 @@ import mcp.MethodsReturnNonnullByDefault;
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
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.passive.fish.PufferfishEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.Explosion;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
|
@ -39,16 +35,11 @@ public class DrowningCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<DrowningCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x2D41F4, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - water
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x2D41F4 ).weight( BestiaryInfo.DefaultWeight.LOW ).theme( BestiaryInfo.Theme.WATER )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 ).drownImmune().fluidPushImmune()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -69,15 +60,15 @@ public class DrowningCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<DrowningCreeperEntity> getVariantFactory() { return DrowningCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends DrowningCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public DrowningCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setCanBreatheInWater( true );
|
||||
getSpecialData().setIgnoreWaterPush( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
public DrowningCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius ) + 3.0F; }
|
||||
|
@ -147,7 +138,6 @@ public class DrowningCreeperEntity extends _SpecialCreeperEntity {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/** Helper method to simplify spawning pufferfish. */
|
||||
private void spawnPufferfish( BlockPos pos ) {
|
||||
if( !(level instanceof IServerWorld) ) return;
|
||||
|
@ -164,13 +154,4 @@ public class DrowningCreeperEntity extends _SpecialCreeperEntity {
|
|||
|
||||
@Override
|
||||
public boolean isInWaterRainOrBubble() { return true; }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "drowning" ),
|
||||
GET_TEXTURE_PATH( "drowning_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,15 +3,15 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.config.species.CreeperSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
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.entity.*;
|
||||
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.ai.goal.NearestAttackableTargetGoal;
|
||||
|
@ -49,16 +49,16 @@ public class EnderCreeperEntity extends _SpecialCreeperEntity implements IAngera
|
|||
public static MobFamily.Species<EnderCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xCC00FA, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - the end
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xCC00FA ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 ).waterSensitive()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new CreeperSpeciesConfig( species, true, false, false );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -76,15 +76,15 @@ public class EnderCreeperEntity extends _SpecialCreeperEntity implements IAngera
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<EnderCreeperEntity> getVariantFactory() { return EnderCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends EnderCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public EnderCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
setCannotExplodeWhileWet( true );
|
||||
xpReward += 2;
|
||||
}
|
||||
public EnderCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
|
@ -107,15 +107,6 @@ public class EnderCreeperEntity extends _SpecialCreeperEntity implements IAngera
|
|||
readPersistentAngerSaveData( (ServerWorld) level, saveTag );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "ender" ),
|
||||
GET_TEXTURE_PATH( "ender_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- IAngerable Implementations ----------------
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.config.species.CreeperSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
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.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -26,10 +26,15 @@ public class FireCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<FireCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0xE13916 );
|
||||
//TODO theme - fire
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xE13916 ).theme( BestiaryInfo.Theme.FIRE )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 ).fireImmune().waterSensitive();
|
||||
}
|
||||
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new CreeperSpeciesConfig( species, true, false, false );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -48,27 +53,19 @@ public class FireCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<FireCreeperEntity> getVariantFactory() { return FireCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends FireCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public FireCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
setCannotExplodeWhileWet( true );
|
||||
xpReward += 1;
|
||||
}
|
||||
public FireCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion. */
|
||||
@Override
|
||||
protected void makeVariantExplosion( float explosionPower ) {
|
||||
ExplosionHelper.explode( this, explosionPower, true, true );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "fire" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -9,11 +9,9 @@ import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
|||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.Explosion;
|
||||
|
@ -32,8 +30,10 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<GravelCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x908884 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x908884 )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 ).burnImmune();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -52,14 +52,15 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<GravelCreeperEntity> getVariantFactory() { return GravelCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends GravelCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public GravelCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setImmuneToBurning( true );
|
||||
xpReward += 1;
|
||||
}
|
||||
public GravelCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius / 2.0F ); }
|
||||
|
@ -106,12 +107,4 @@ public class GravelCreeperEntity extends _SpecialCreeperEntity {
|
|||
}
|
||||
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; }
|
||||
}
|
|
@ -5,16 +5,12 @@ import fathertoast.specialmobs.common.bestiary.MobFamily;
|
|||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
import fathertoast.specialmobs.common.entity.ai.goal.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;
|
||||
|
@ -30,16 +26,11 @@ public class JumpingCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<JumpingCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x7D6097 );
|
||||
//TODO theme - mountain
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x7D6097 ).theme( BestiaryInfo.Theme.MOUNTAIN )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 ).fallImmune()
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -57,14 +48,15 @@ public class JumpingCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<JumpingCreeperEntity> getVariantFactory() { return JumpingCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends JumpingCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public JumpingCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setFallDamageMultiplier( 0.0F );
|
||||
xpReward += 2;
|
||||
}
|
||||
public JumpingCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
|
@ -72,12 +64,4 @@ public class JumpingCreeperEntity extends _SpecialCreeperEntity {
|
|||
AIHelper.insertGoal( goalSelector, 4, new SpecialLeapAtTargetGoal(
|
||||
this, 10, 6.0F, 10.0F, 1.3F, 2.0F ) );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "jumping" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -8,9 +8,7 @@ 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.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.IServerWorldInfo;
|
||||
|
||||
|
@ -27,9 +25,10 @@ public class LightningCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<LightningCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0x499CAE );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x499CAE )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 ).fireImmune();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -47,13 +46,15 @@ public class LightningCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<LightningCreeperEntity> getVariantFactory() { return LightningCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends LightningCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public LightningCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 1;
|
||||
}
|
||||
public LightningCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
@Override
|
||||
|
@ -95,12 +96,4 @@ public class LightningCreeperEntity extends _SpecialCreeperEntity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "lightning" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,13 +3,10 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -26,16 +23,10 @@ public class MiniCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<MiniCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.5F, 0.9F );
|
||||
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFC0CB ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.size( 0.5F, 0.5F, 0.9F )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -52,13 +43,15 @@ public class MiniCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<MiniCreeperEntity> getVariantFactory() { return MiniCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends MiniCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public MiniCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.5F );
|
||||
}
|
||||
public MiniCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this creeper's explosion power multiplier. */
|
||||
protected float getVariantExplosionPower( float radius ) { return super.getVariantExplosionPower( radius / 2.0F ); }
|
||||
|
|
|
@ -4,15 +4,12 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.CreatureAttribute;
|
||||
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.FleeSunGoal;
|
||||
import net.minecraft.entity.ai.goal.RestrictSunGoal;
|
||||
|
@ -21,7 +18,6 @@ import net.minecraft.entity.projectile.ProjectileHelper;
|
|||
import net.minecraft.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.BowItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
|
@ -40,17 +36,12 @@ public class SkeletonCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<SkeletonCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xC1C1C1 );
|
||||
//TODO theme - forest
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, -4.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xC1C1C1 ).theme( BestiaryInfo.Theme.FOREST )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, -4.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -68,13 +59,15 @@ public class SkeletonCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<SkeletonCreeperEntity> getVariantFactory() { return SkeletonCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends SkeletonCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public SkeletonCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 1;
|
||||
}
|
||||
public SkeletonCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
|
@ -140,12 +133,4 @@ public class SkeletonCreeperEntity extends _SpecialCreeperEntity {
|
|||
}
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "skeleton" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,20 +3,18 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SplittingCreeperSpeciesConfig;
|
||||
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.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.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -35,18 +33,23 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
public static MobFamily.Species<SplittingCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.7F, 1.99F );
|
||||
return new BestiaryInfo( 0x5F9D22, BestiaryInfo.BaseWeight.LOW );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x5F9D22 ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithEyes()
|
||||
.size( 1.2F, 0.7F, 1.99F )
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialCreeperEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new SplittingCreeperSpeciesConfig( species, false, false, true,
|
||||
1, 3 );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
public SplittingCreeperSpeciesConfig getConfig() { return (SplittingCreeperSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Splitting Creeper",
|
||||
|
@ -62,21 +65,22 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<SplittingCreeperEntity> getVariantFactory() { return SplittingCreeperEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends SplittingCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public SplittingCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.2F );
|
||||
getSpecialData().setImmuneToBurning( true );
|
||||
setExplodesWhenShot( true );
|
||||
xpReward += 2;
|
||||
extraBabies = random.nextInt( 4 );
|
||||
}
|
||||
|
||||
/** The number of extra mini creepers spawned on explosion (in addition to the amount based on explosion power). */
|
||||
private int extraBabies;
|
||||
|
||||
public SplittingCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
extraBabies = getConfig().SPLITTING.extraBabies.next( random );
|
||||
}
|
||||
|
||||
/** Override to change this creeper's explosion. */
|
||||
@Override
|
||||
protected void makeVariantExplosion( float explosionPower ) {
|
||||
|
@ -104,9 +108,8 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
baby.yBodyRot = yRot;
|
||||
groupData = baby.finalizeSpawn( (IServerWorld) level, level.getCurrentDifficultyAt( blockPosition() ),
|
||||
SpawnReason.MOB_SUMMONED, groupData, null );
|
||||
baby.copyChargedState( this );
|
||||
baby.setTarget( getTarget() );
|
||||
if( isPowered() ) baby.getEntityData().set( DATA_IS_POWERED, true );
|
||||
if ( isSupercharged() ) baby.getEntityData().set( IS_SUPERCHARGED, true );
|
||||
|
||||
baby.setDeltaMovement(
|
||||
(random.nextDouble() - 0.5) * speed,
|
||||
|
@ -130,13 +133,4 @@ public class SplittingCreeperEntity extends _SpecialCreeperEntity {
|
|||
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( "splitting" ),
|
||||
GET_TEXTURE_PATH( "splitting_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,9 +3,11 @@ package fathertoast.specialmobs.common.entity.creeper;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.CreeperSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.ai.IExplodingMob;
|
||||
import fathertoast.specialmobs.common.util.ExplosionHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
|
@ -24,7 +26,6 @@ import net.minecraft.network.datasync.EntityDataManager;
|
|||
import net.minecraft.pathfinding.PathNodeType;
|
||||
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;
|
||||
|
@ -39,7 +40,7 @@ import java.util.List;
|
|||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<_SpecialCreeperEntity> {
|
||||
public class _SpecialCreeperEntity extends CreeperEntity implements IExplodingMob, ISpecialMob<_SpecialCreeperEntity> {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
|
@ -47,15 +48,23 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
public static MobFamily.Species<_SpecialCreeperEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x000000 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x000000 )
|
||||
.vanillaTextureBaseOnly( "textures/entity/creeper/creeper.png" )
|
||||
.experience( 5 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return CreeperEntity.createAttributes();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new CreeperSpeciesConfig( species, false, false, false );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
public CreeperSpeciesConfig getConfig() { return (CreeperSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() { return CreeperEntity.createAttributes(); }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Creeper",
|
||||
|
@ -73,11 +82,6 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
|
@ -96,6 +100,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
}
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@SuppressWarnings( "unused" ) // Not normally used for creepers
|
||||
protected void onVariantAttack( Entity target ) { }
|
||||
|
||||
/** Called to perform this creeper's explosion 'attack'. */
|
||||
|
@ -159,13 +164,21 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
/** The parameter for special mob render scale. */
|
||||
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialCreeperEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
public _SpecialCreeperEntity( EntityType<? extends _SpecialCreeperEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
setCannotExplodeWhileWet( !getConfig().CREEPERS.canExplodeWhileWet.get() );
|
||||
setExplodesWhileBurning( getConfig().CREEPERS.explodesWhileBurning.get() );
|
||||
setExplodesWhenShot( getConfig().CREEPERS.explodesWhenShot.get() );
|
||||
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
entityData.define( EXPLODE_FLAGS, (byte) 0 );
|
||||
entityData.define( IS_SUPERCHARGED, false );
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
|
@ -188,9 +201,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
/** Called when this entity is struck by lightning. */
|
||||
@Override
|
||||
public void thunderHit( ServerWorld world, LightningBoltEntity lightningBolt ) {
|
||||
if( !isPowered() && random.nextDouble() < 0.1 ) // TODO config
|
||||
setSupercharged( true );
|
||||
|
||||
charge();
|
||||
super.thunderHit( world, lightningBolt );
|
||||
|
||||
// Make it less likely for charged "explode while burning" creepers to immediately explode
|
||||
|
@ -202,8 +213,13 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
public ILivingEntityData finalizeSpawn( IServerWorld world, DifficultyInstance difficulty, SpawnReason spawnReason,
|
||||
@Nullable ILivingEntityData groupData, @Nullable CompoundNBT eggTag ) {
|
||||
groupData = super.finalizeSpawn( world, difficulty, spawnReason, groupData, eggTag );
|
||||
if( world.getLevelData().isThundering() && random.nextDouble() < 0.01 ) { //TODO config
|
||||
getEntityData().set( DATA_IS_POWERED, true );
|
||||
|
||||
if( world.getLevelData().isThundering() ) {
|
||||
final double chargedChance = getConfig().CREEPERS.stormChargeChance.get() < 0.0 ?
|
||||
MobFamily.CREEPER.config.CREEPERS.familyStormChargeChance.get() :
|
||||
getConfig().CREEPERS.stormChargeChance.get();
|
||||
|
||||
if( random.nextDouble() < chargedChance ) charge();
|
||||
}
|
||||
return groupData;
|
||||
}
|
||||
|
@ -213,31 +229,48 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
|
||||
/** The parameter for creeper explosion properties. This is a combination of boolean flags. */
|
||||
private static final DataParameter<Byte> EXPLODE_FLAGS = EntityDataManager.defineId( _SpecialCreeperEntity.class, DataSerializers.BYTE );
|
||||
protected static final DataParameter<Boolean> IS_SUPERCHARGED = EntityDataManager.defineId( _SpecialCreeperEntity.class, DataSerializers.BOOLEAN );
|
||||
|
||||
/** The bit for "is supercharged". */
|
||||
private static final byte EXPLODE_FLAG_SUPERCHARGED = 0b0001;
|
||||
/** The bit for "cannot explode while wet". */
|
||||
private static final byte EXPLODE_FLAG_DEFUSE_IN_WATER = 0b0001;
|
||||
private static final byte EXPLODE_FLAG_DEFUSE_IN_WATER = 0b0010;
|
||||
/** The bit for "explodes while burning". */
|
||||
private static final byte EXPLODE_FLAG_ON_FIRE = 0b0010;
|
||||
private static final byte EXPLODE_FLAG_ON_FIRE = 0b0100;
|
||||
/** The bit for "explodes when shot". */
|
||||
private static final byte EXPLODE_FLAG_WHEN_SHOT = 0b0100;
|
||||
private static final byte EXPLODE_FLAG_WHEN_SHOT = 0b1000;
|
||||
|
||||
|
||||
/** @return True if this creeper is super charged. */
|
||||
public boolean isSupercharged() {
|
||||
return entityData.get( IS_SUPERCHARGED );
|
||||
/** Called to charge this creeper, potentially supercharging it. */
|
||||
public void charge() {
|
||||
if( !isPowered() ) {
|
||||
setPowered( true );
|
||||
if( MobFamily.CREEPER.config.CREEPERS.superchargeChance.rollChance( random ) )
|
||||
setSupercharged( true );
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy another creeper's charged state. */
|
||||
public void copyChargedState( _SpecialCreeperEntity other ) {
|
||||
setPowered( other.isPowered() );
|
||||
setSupercharged( other.isSupercharged() );
|
||||
}
|
||||
|
||||
/** Sets this creeper's charged state to the given value. */
|
||||
private void setPowered( boolean charged ) { entityData.set( DATA_IS_POWERED, charged ); }
|
||||
|
||||
/** @return True if this creeper is super charged. */
|
||||
public boolean isSupercharged() { return getExplodeFlag( EXPLODE_FLAG_SUPERCHARGED ); }
|
||||
|
||||
/** Sets this creeper's supercharged state to the given value. */
|
||||
public void setSupercharged( boolean superCharged ) {
|
||||
entityData.set( IS_SUPERCHARGED, superCharged );
|
||||
private void setSupercharged( boolean value ) {
|
||||
if( value && !isPowered() ) setPowered( true );
|
||||
setExplodeFlag( EXPLODE_FLAG_SUPERCHARGED, value );
|
||||
}
|
||||
|
||||
/** @return True if this creeper is unable to explode while wet. */
|
||||
public boolean cannotExplodeWhileWet() { return getExplodeFlag( EXPLODE_FLAG_DEFUSE_IN_WATER ); }
|
||||
|
||||
/** Sets this creeper's capability to explode while wet. */
|
||||
public void setCannotExplodeWhileWet( boolean value ) {
|
||||
private void setCannotExplodeWhileWet( boolean value ) {
|
||||
setExplodeFlag( EXPLODE_FLAG_DEFUSE_IN_WATER, value );
|
||||
setPathfindingMalus( PathNodeType.WATER, value ? PathNodeType.LAVA.getMalus() : PathNodeType.WATER.getMalus() );
|
||||
}
|
||||
|
@ -246,7 +279,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
public boolean explodesWhileBurning() { return getExplodeFlag( EXPLODE_FLAG_ON_FIRE ); }
|
||||
|
||||
/** Sets this creeper's property to explode while burning. */
|
||||
public void setExplodesWhileBurning( boolean value ) {
|
||||
private void setExplodesWhileBurning( boolean value ) {
|
||||
setExplodeFlag( EXPLODE_FLAG_ON_FIRE, value );
|
||||
if( value ) {
|
||||
setPathfindingMalus( PathNodeType.DANGER_FIRE, PathNodeType.DAMAGE_FIRE.getMalus() );
|
||||
|
@ -262,7 +295,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
public boolean explodesWhenShot() { return getExplodeFlag( EXPLODE_FLAG_WHEN_SHOT ); }
|
||||
|
||||
/** Sets this creeper's property to explode when shot. */
|
||||
public void setExplodesWhenShot( boolean value ) { setExplodeFlag( EXPLODE_FLAG_WHEN_SHOT, value ); }
|
||||
private void setExplodesWhenShot( boolean value ) { setExplodeFlag( EXPLODE_FLAG_WHEN_SHOT, value ); }
|
||||
|
||||
/** @return The value for a specific explode flag. */
|
||||
private boolean getExplodeFlag( byte flag ) { return (entityData.get( EXPLODE_FLAGS ) & flag) != 0; }
|
||||
|
@ -284,6 +317,11 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
@Override
|
||||
public SpecialMobData<_SpecialCreeperEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialCreeperEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final int getExperience() { return xpReward; }
|
||||
|
@ -292,16 +330,6 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
@Override
|
||||
public final void setExperience( int xp ) { xpReward = xp; }
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "creeper/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = { new ResourceLocation( "textures/entity/creeper/creeper.png" ) };
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
@ -388,7 +416,7 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
saveTag.putBoolean( References.TAG_SUPERCHARGED, isSupercharged() );
|
||||
|
||||
saveTag.putBoolean( References.TAG_DRY_EXPLODE, cannotExplodeWhileWet() );
|
||||
saveTag.putBoolean( References.TAG_WHEN_BURNING_EXPLODE, explodesWhileBurning() );
|
||||
saveTag.putBoolean( References.TAG_WHILE_BURNING_EXPLODE, explodesWhileBurning() );
|
||||
saveTag.putBoolean( References.TAG_WHEN_SHOT_EXPLODE, explodesWhenShot() );
|
||||
|
||||
getSpecialData().writeToNBT( saveTag );
|
||||
|
@ -407,8 +435,8 @@ public class _SpecialCreeperEntity extends CreeperEntity implements ISpecialMob<
|
|||
|
||||
if( saveTag.contains( References.TAG_DRY_EXPLODE, References.NBT_TYPE_NUMERICAL ) )
|
||||
setCannotExplodeWhileWet( saveTag.getBoolean( References.TAG_DRY_EXPLODE ) );
|
||||
if( saveTag.contains( References.TAG_WHEN_BURNING_EXPLODE, References.NBT_TYPE_NUMERICAL ) )
|
||||
setExplodesWhileBurning( saveTag.getBoolean( References.TAG_WHEN_BURNING_EXPLODE ) );
|
||||
if( saveTag.contains( References.TAG_WHILE_BURNING_EXPLODE, References.NBT_TYPE_NUMERICAL ) )
|
||||
setExplodesWhileBurning( saveTag.getBoolean( References.TAG_WHILE_BURNING_EXPLODE ) );
|
||||
if( saveTag.contains( References.TAG_WHEN_SHOT_EXPLODE, References.NBT_TYPE_NUMERICAL ) )
|
||||
setExplodesWhenShot( saveTag.getBoolean( References.TAG_WHEN_SHOT_EXPLODE ) );
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import net.minecraft.entity.LivingEntity;
|
|||
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;
|
||||
|
@ -27,9 +26,10 @@ public class BlindingEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<BlindingEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xFFFFFF );
|
||||
//TODO theme - forest
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFFFFF ).theme( BestiaryInfo.Theme.FOREST )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 1 ).effectImmune( Effects.BLINDNESS );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -47,14 +47,15 @@ public class BlindingEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<BlindingEndermanEntity> getVariantFactory() { return BlindingEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends BlindingEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public BlindingEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().addPotionImmunity( Effects.BLINDNESS );
|
||||
xpReward += 1;
|
||||
}
|
||||
public BlindingEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Called each tick to update this entity's movement. */
|
||||
@Override
|
||||
|
@ -68,13 +69,4 @@ public class BlindingEndermanEntity extends _SpecialEndermanEntity {
|
|||
target.removeEffect( Effects.NIGHT_VISION ); // Prevent blind + night vision combo (black screen)
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "blinding" ),
|
||||
GET_TEXTURE_PATH( "blinding_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -25,7 +25,6 @@ import net.minecraft.potion.Effects;
|
|||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -45,9 +44,11 @@ public class IcyEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<IcyEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x72959C );
|
||||
//TODO theme - ice
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x72959C ).theme( BestiaryInfo.Theme.ICE )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 1 ).effectImmune( Effects.MOVEMENT_SLOWDOWN );
|
||||
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -66,14 +67,16 @@ public class IcyEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<IcyEndermanEntity> getVariantFactory() { return IcyEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends IcyEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public IcyEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().addPotionImmunity( Effects.MOVEMENT_SLOWDOWN );
|
||||
xpReward += 1;
|
||||
|
||||
setPathfindingMalus( PathNodeType.WATER, PathNodeType.WALKABLE.getMalus() );
|
||||
}
|
||||
|
||||
|
@ -189,13 +192,4 @@ public class IcyEndermanEntity extends _SpecialEndermanEntity {
|
|||
FrostWalkerEnchantment.onEntityMoved( this, level, pos, 1 );
|
||||
onGround = actualOnGround;
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "icy" ),
|
||||
GET_TEXTURE_PATH( "icy_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -12,7 +12,6 @@ import net.minecraft.entity.EntityType;
|
|||
import net.minecraft.entity.LivingEntity;
|
||||
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;
|
||||
|
||||
|
@ -29,9 +28,10 @@ public class LightningEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<LightningEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0x4BB4B5 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x4BB4B5 )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 ).fireImmune();
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -49,13 +49,15 @@ public class LightningEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<LightningEndermanEntity> getVariantFactory() { return LightningEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends LightningEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public LightningEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
public LightningEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
|
@ -71,13 +73,4 @@ 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" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,13 +3,10 @@ package fathertoast.specialmobs.common.entity.enderman;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -26,17 +23,12 @@ public class MiniEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<MiniEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 0.5F, 0.99F );
|
||||
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialEndermanEntity.createAttributes() )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, -2.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.3 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFC0CB ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.size( 0.35F, 0.5F, 0.99F )
|
||||
.addExperience( 1 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, -2.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.3 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -53,15 +45,16 @@ public class MiniEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<MiniEndermanEntity> getVariantFactory() { return MiniEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends MiniEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public MiniEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.35F );
|
||||
maxUpStep = 0.5F;
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
// None
|
||||
}
|
|
@ -3,19 +3,15 @@ package fathertoast.specialmobs.common.entity.enderman;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.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.nbt.CompoundNBT;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -31,16 +27,11 @@ public class MirageEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<MirageEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xC2BC84, BestiaryInfo.BaseWeight.LOW );
|
||||
//TODO theme - desert
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialEndermanEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xC2BC84 ).weight( BestiaryInfo.DefaultWeight.LOW ).theme( BestiaryInfo.Theme.DESERT )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -60,21 +51,23 @@ public class MirageEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<MirageEndermanEntity> getVariantFactory() { return MirageEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends MirageEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public MirageEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
/** Whether this mirage enderman is fake. */
|
||||
public boolean isFake = false;
|
||||
|
||||
public MirageEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Sets this mirage enderman as fake. */
|
||||
public void setFake() {
|
||||
isFake = true;
|
||||
xpReward = 0;
|
||||
setExperience( 0 );
|
||||
//noinspection ConstantConditions
|
||||
getAttribute( Attributes.ATTACK_DAMAGE ).setBaseValue( 0.0 );
|
||||
}
|
||||
|
@ -112,18 +105,14 @@ public class MirageEndermanEntity extends _SpecialEndermanEntity {
|
|||
protected boolean teleport( double x, double y, double z ) {
|
||||
if( isFake ) return false;
|
||||
|
||||
double xI = getX();
|
||||
double yI = getY();
|
||||
double zI = getZ();
|
||||
|
||||
if( super.teleport( x, y, z ) ) {
|
||||
mirage( xI, yI, zI );
|
||||
mirage();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void mirage( double xI, double yI, double zI ) {
|
||||
private void mirage() {
|
||||
if( !isFake && getTarget() != null ) {
|
||||
final MirageEndermanEntity mirage = SPECIES.entityType.get().create( level );
|
||||
if( mirage == null ) return;
|
||||
|
@ -134,10 +123,10 @@ public class MirageEndermanEntity extends _SpecialEndermanEntity {
|
|||
|
||||
// Return one of the endermen to the initial position (either the real or the fake)
|
||||
if( random.nextInt( 4 ) == 0 ) {
|
||||
moveTo( xI, yI, zI );
|
||||
moveTo( xo, yo, zo );
|
||||
}
|
||||
else {
|
||||
mirage.moveTo( xI, yI, zI );
|
||||
mirage.moveTo( xo, yo, zo );
|
||||
}
|
||||
|
||||
mirage.setHealth( getHealth() );
|
||||
|
@ -163,13 +152,4 @@ public class MirageEndermanEntity extends _SpecialEndermanEntity {
|
|||
if( saveTag.contains( References.TAG_IS_FAKE, References.NBT_TYPE_NUMERICAL ) )
|
||||
isFake = saveTag.getBoolean( References.TAG_IS_FAKE );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "mirage" ),
|
||||
GET_TEXTURE_PATH( "mirage_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,17 +3,14 @@ package fathertoast.specialmobs.common.entity.enderman;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -33,15 +30,11 @@ public class ThiefEndermanEntity extends _SpecialEndermanEntity {
|
|||
public static MobFamily.Species<ThiefEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x04FA00, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialEndermanEntity.createAttributes() )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 1.2 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x04FA00 ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithEyes()
|
||||
.addExperience( 2 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -59,16 +52,18 @@ public class ThiefEndermanEntity extends _SpecialEndermanEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<ThiefEndermanEntity> getVariantFactory() { return ThiefEndermanEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends ThiefEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public ThiefEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
private int teleportTargetDelay;
|
||||
|
||||
public ThiefEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
|
@ -118,13 +113,4 @@ public class ThiefEndermanEntity extends _SpecialEndermanEntity {
|
|||
super.aiStep();
|
||||
if( !level.isClientSide() ) teleportTargetDelay--;
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "thief" ),
|
||||
GET_TEXTURE_PATH( "thief_eyes" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.common.entity.enderman;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
|
@ -19,13 +18,9 @@ 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
|
||||
|
@ -39,14 +34,14 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
public static MobFamily.Species<_SpecialEndermanEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x000000 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x000000 )
|
||||
.vanillaTextureWithEyes( "textures/entity/enderman/enderman.png", "textures/entity/enderman/enderman_eyes.png" )
|
||||
.experience( 5 ).waterSensitive();
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return EndermanEntity.createAttributes();
|
||||
}
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() { return EndermanEntity.createAttributes(); }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
|
@ -65,12 +60,6 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
getSpecialData().setDamagedByWater( true );
|
||||
}
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
|
@ -103,20 +92,16 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
/** The parameter for special mob render scale. */
|
||||
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialEndermanEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
public _SpecialEndermanEntity( EntityType<? extends _SpecialEndermanEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** 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 anything?
|
||||
return groupData;
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,6 +113,11 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
@Override
|
||||
public SpecialMobData<_SpecialEndermanEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialEndermanEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final int getExperience() { return xpReward; }
|
||||
|
@ -136,19 +126,6 @@ public class _SpecialEndermanEntity extends EndermanEntity implements ISpecialMo
|
|||
@Override
|
||||
public final void setExperience( int xp ) { xpReward = xp; }
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "enderman/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/enderman/enderman.png" ),
|
||||
new ResourceLocation( "textures/entity/enderman/enderman_eyes.png" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package fathertoast.specialmobs.common.entity.ghast;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
|
@ -28,16 +25,11 @@ public class BabyGhastEntity extends _SpecialGhastEntity {
|
|||
public static MobFamily.Species<BabyGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 1.0F, 1.0F );
|
||||
return new BestiaryInfo( 0xFFC0CB, BestiaryInfo.BaseWeight.DISABLED );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, -1.0 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFFC0CB ).weight( BestiaryInfo.DefaultWeight.DISABLED )
|
||||
.size( 0.25F, 1.0F, 1.0F )
|
||||
.experience( 1 ).disableRangedAttack()
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, -1.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -54,21 +46,15 @@ public class BabyGhastEntity extends _SpecialGhastEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<BabyGhastEntity> getVariantFactory() { return BabyGhastEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends BabyGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public BabyGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.25F );
|
||||
xpReward = 1;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage -= 1.0F;
|
||||
disableRangedAI();
|
||||
}
|
||||
public BabyGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** @return The sound this entity makes idly. */
|
||||
@Override
|
||||
|
|
|
@ -4,126 +4,117 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.register.SMItems;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.projectile.CorporealShiftFireballEntity;
|
||||
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.nbt.CompoundNBT;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SpecialMob
|
||||
public class CorporealShiftGhastEntity extends _SpecialGhastEntity {
|
||||
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
|
||||
@SpecialMob.SpeciesReference
|
||||
public static MobFamily.Species<CorporealShiftGhastEntity> SPECIES;
|
||||
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo(EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 6.0F, 6.0F );
|
||||
return new BestiaryInfo( 0xA7FF9B, BestiaryInfo.BaseWeight.LOW );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xA7FF9B ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithAnimation()
|
||||
.addExperience( 4 ).regen( 80 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 0.8 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addAttribute( Attributes.ARMOR, 0.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 0.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.8 )
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Corporeal Shift Ghast",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
|
||||
@SpecialMob.LootTableProvider
|
||||
public static void buildLootTable( LootTableBuilder loot ) {
|
||||
addBaseLoot( loot );
|
||||
// TODO - Uh uhm uhhhhh hmmm..
|
||||
loot.addSemicommonDrop( "semicommon", SMItems.INCORPOREAL_FIREBALL.get() );
|
||||
}
|
||||
|
||||
|
||||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<CorporealShiftGhastEntity> getVariantFactory() { return CorporealShiftGhastEntity::new; }
|
||||
|
||||
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends CorporealShiftGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public static final DataParameter<Boolean> CORPOREAL = EntityDataManager.defineId(CorporealShiftGhastEntity.class, DataSerializers.BOOLEAN);
|
||||
|
||||
|
||||
public static final DataParameter<Boolean> CORPOREAL = EntityDataManager.defineId( CorporealShiftGhastEntity.class, DataSerializers.BOOLEAN );
|
||||
|
||||
private final int maxShiftTime = 600;
|
||||
private int shiftTime = maxShiftTime;
|
||||
|
||||
public CorporealShiftGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setRegenerationTime( 80 );
|
||||
getSpecialData().setBaseScale( 1.0F );
|
||||
xpReward += 2;
|
||||
}
|
||||
|
||||
|
||||
public CorporealShiftGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
entityData.define(CORPOREAL, false);
|
||||
entityData.define( CORPOREAL, false );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if ( --shiftTime <= 0 ) {
|
||||
if ( !level.isClientSide ) {
|
||||
|
||||
if( --shiftTime <= 0 ) {
|
||||
if( !level.isClientSide ) {
|
||||
shiftTime = maxShiftTime;
|
||||
entityData.set(CORPOREAL, !entityData.get(CORPOREAL));
|
||||
spawnShiftSmoke((ServerWorld)level);
|
||||
setCorporeal( !isCorporeal() );
|
||||
spawnShiftSmoke( (ServerWorld) level );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnShiftSmoke(ServerWorld world) {
|
||||
world.sendParticles(ParticleTypes.CLOUD, this.getX(), this.getY(), this.getZ(), 25, 0.0, 0.0, 0.0, 0.4);
|
||||
|
||||
private void spawnShiftSmoke( ServerWorld world ) {
|
||||
world.sendParticles( ParticleTypes.CLOUD, this.getX(), this.getY(), this.getZ(), 25, 0.0, 0.0, 0.0, 0.4 );
|
||||
}
|
||||
|
||||
public boolean isCorporeal() {
|
||||
return entityData.get(CORPOREAL);
|
||||
}
|
||||
|
||||
|
||||
public boolean isCorporeal() { return entityData.get( CORPOREAL ); }
|
||||
|
||||
private void setCorporeal( boolean value ) { entityData.set( CORPOREAL, value ); }
|
||||
|
||||
/** Override to change this ghast's explosion power multiplier. */
|
||||
@Override
|
||||
protected int getVariantExplosionPower( int radius ) { return Math.round( radius * 2.5F ); }
|
||||
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
@Override
|
||||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
if( !isSilent() ) level.levelEvent( null, References.EVENT_GHAST_SHOOT, blockPosition(), 0 );
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().rangedAttackSpread;
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().getRangedAttackSpread();
|
||||
final Vector3d lookVec = getViewVector( 1.0F ).scale( getBbWidth() );
|
||||
double dX = target.getX() - (getX() + lookVec.x) + getRandom().nextGaussian() * accelVariance;
|
||||
double dY = target.getY( 0.5 ) - (0.5 + getY( 0.5 ));
|
||||
double dZ = target.getZ() - (getZ() + lookVec.z) + getRandom().nextGaussian() * accelVariance;
|
||||
|
||||
|
||||
final CorporealShiftFireballEntity fireball = new CorporealShiftFireballEntity( level, this, dX, dY, dZ );
|
||||
fireball.explosionPower = getVariantExplosionPower( getExplosionPower() );
|
||||
fireball.setPos(
|
||||
|
@ -132,40 +123,29 @@ public class CorporealShiftGhastEntity extends _SpecialGhastEntity {
|
|||
getZ() + lookVec.z );
|
||||
level.addFreshEntity( fireball );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "corporeal_shift" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "corporeal_shift_shoot" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
||||
/** @return Attempts to damage this entity; returns true if the hit was successful. */
|
||||
@Override
|
||||
public boolean hurt(DamageSource source, float amount ) {
|
||||
return isCorporeal() && super.hurt(source, amount);
|
||||
public boolean hurt( DamageSource source, float amount ) {
|
||||
return isCorporeal() && super.hurt( source, amount );
|
||||
}
|
||||
|
||||
/** Saves data to this entity's base NBT compound that is specific to its subclass. */
|
||||
|
||||
/** Override to save data to this entity's NBT data. */
|
||||
@Override
|
||||
public void addAdditionalSaveData( CompoundNBT tag ) {
|
||||
super.addAdditionalSaveData( tag );
|
||||
tag.putInt("ShiftTime", shiftTime);
|
||||
public void addVariantSaveData( CompoundNBT saveTag ) {
|
||||
saveTag.putBoolean( References.TAG_IS_SHIFTED, isCorporeal() );
|
||||
saveTag.putShort( References.TAG_SHIFT_TIME, (short) shiftTime );
|
||||
}
|
||||
|
||||
/** Loads data from this entity's base NBT compound that is specific to its subclass. */
|
||||
|
||||
/** Override to load data from this entity's NBT data. */
|
||||
@Override
|
||||
public void readAdditionalSaveData( CompoundNBT tag ) {
|
||||
super.readAdditionalSaveData( tag );
|
||||
|
||||
if (tag.contains("ShiftTime", Constants.NBT.TAG_ANY_NUMERIC)) {
|
||||
shiftTime = tag.getInt("ShiftTime");
|
||||
}
|
||||
public void readVariantSaveData( CompoundNBT saveTag ) {
|
||||
if( saveTag.contains( References.TAG_IS_SHIFTED, References.NBT_TYPE_NUMERICAL ) )
|
||||
setCorporeal( saveTag.getBoolean( References.TAG_IS_SHIFTED ) );
|
||||
if( saveTag.contains( References.TAG_SHIFT_TIME, References.NBT_TYPE_NUMERICAL ) )
|
||||
shiftTime = saveTag.getShort( References.TAG_SHIFT_TIME );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,17 +4,14 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -30,19 +27,14 @@ public class FighterGhastEntity extends _SpecialGhastEntity {
|
|||
public static MobFamily.Species<FighterGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 2.0F, 2.0F );
|
||||
return new BestiaryInfo( 0x7A1300 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addAttribute( Attributes.ARMOR, 10.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.8 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x7A1300 )
|
||||
.uniqueTextureWithAnimation()
|
||||
.size( 0.5F, .0F, 2.0F )
|
||||
.addExperience( 1 ).disableRangedAttack()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 ).addToAttribute( Attributes.ARMOR, 10.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 0.8 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -60,21 +52,15 @@ public class FighterGhastEntity extends _SpecialGhastEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<FighterGhastEntity> getVariantFactory() { return FighterGhastEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends FighterGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public FighterGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.5F );
|
||||
xpReward += 1;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 2.0F;
|
||||
disableRangedAI();
|
||||
}
|
||||
public FighterGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
|
@ -82,14 +68,4 @@ public class FighterGhastEntity extends _SpecialGhastEntity {
|
|||
MobHelper.causeLifeLoss( (LivingEntity) target, 2.0F );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "fighter" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "fighter_shooting" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,16 +3,12 @@ package fathertoast.specialmobs.common.entity.ghast;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -28,19 +24,14 @@ public class KingGhastEntity extends _SpecialGhastEntity {
|
|||
public static MobFamily.Species<KingGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 6.0F, 6.0F );
|
||||
return new BestiaryInfo( 0xE8C51A, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addAttribute( Attributes.ARMOR, 10.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 4.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.6 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xE8C51A ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithAnimation()
|
||||
.size( 1.5F, 6.0F, 6.0F )
|
||||
.addExperience( 4 ).regen( 30 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 ).addToAttribute( Attributes.ARMOR, 10.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 4.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 0.6 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -59,33 +50,17 @@ public class KingGhastEntity extends _SpecialGhastEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<KingGhastEntity> getVariantFactory() { return KingGhastEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends KingGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public KingGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
getSpecialData().setRegenerationTime( 30 );
|
||||
xpReward += 4;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 4.0F;
|
||||
}
|
||||
public KingGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this ghast's explosion power multiplier. */
|
||||
@Override
|
||||
protected int getVariantExplosionPower( int radius ) { return Math.round( radius * 2.5F ); }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "king" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "king_shooting" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,8 @@ package fathertoast.specialmobs.common.entity.ghast;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.config.species.QueenGhastSpeciesConfig;
|
||||
import fathertoast.specialmobs.common.config.species.SpeciesConfig;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
@ -11,11 +12,9 @@ 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.ResourceLocation;
|
||||
import net.minecraft.world.IServerWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -33,20 +32,24 @@ public class QueenGhastEntity extends _SpecialGhastEntity {
|
|||
public static MobFamily.Species<QueenGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 5.0F, 5.0F );
|
||||
return new BestiaryInfo( 0xCE0Aff );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xCE0Aff )
|
||||
.uniqueTextureWithAnimation()
|
||||
.size( 1.25F, 5.0F, 5.0F )
|
||||
.addExperience( 2 ).regen( 20 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 0.6 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 20.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.6 )
|
||||
.build();
|
||||
@SpecialMob.ConfigSupplier
|
||||
public static SpeciesConfig createConfig( MobFamily.Species<?> species ) {
|
||||
return new QueenGhastSpeciesConfig( species, 3, 6, 4, 10 );
|
||||
}
|
||||
|
||||
/** @return This entity's species config. */
|
||||
public QueenGhastSpeciesConfig getConfig() { return (QueenGhastSpeciesConfig) getSpecies().config; }
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Queen Ghast",
|
||||
|
@ -63,6 +66,11 @@ public class QueenGhastEntity extends _SpecialGhastEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<QueenGhastEntity> getVariantFactory() { return QueenGhastEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends QueenGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
|
@ -73,18 +81,8 @@ public class QueenGhastEntity extends _SpecialGhastEntity {
|
|||
|
||||
public QueenGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.25F );
|
||||
getSpecialData().setRegenerationTime( 20 );
|
||||
xpReward += 2;
|
||||
|
||||
babies = 3 + random.nextInt( 4 );
|
||||
summons = 4 + random.nextInt( 7 );
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 2.0F;
|
||||
babies = getConfig().QUEEN.babies.next( random );
|
||||
summons = getConfig().QUEEN.summons.next( random );
|
||||
}
|
||||
|
||||
/** Called to attack the target with a ranged attack. */
|
||||
|
@ -160,14 +158,4 @@ public class QueenGhastEntity extends _SpecialGhastEntity {
|
|||
if( saveTag.contains( References.TAG_SUMMONS, References.NBT_TYPE_NUMERICAL ) )
|
||||
summons = saveTag.getByte( References.TAG_SUMMONS );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "queen" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "queen_shooting" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -4,7 +4,6 @@ import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
|||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.MobHelper;
|
||||
import fathertoast.specialmobs.common.util.AttributeHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import fathertoast.specialmobs.datagen.loot.LootTableBuilder;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
@ -12,13 +11,11 @@ import net.minecraft.entity.CreatureAttribute;
|
|||
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.item.Items;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -34,18 +31,14 @@ public class UnholyGhastEntity extends _SpecialGhastEntity {
|
|||
public static MobFamily.Species<UnholyGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 2.0F, 2.0F );
|
||||
return new BestiaryInfo( 0x7AC754, BestiaryInfo.BaseWeight.LOW );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return AttributeHelper.of( _SpecialGhastEntity.createAttributes() )
|
||||
.addAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.addAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multAttribute( Attributes.MOVEMENT_SPEED, 0.7 )
|
||||
.build();
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x7AC754 ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureWithAnimation()
|
||||
.size( 0.5F, 2.0F, 2.0F )
|
||||
.addExperience( 4 ).undead().disableRangedAttack()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 10.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 2.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 0.7 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -64,21 +57,15 @@ public class UnholyGhastEntity extends _SpecialGhastEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<UnholyGhastEntity> getVariantFactory() { return UnholyGhastEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends UnholyGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public UnholyGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 0.5F );
|
||||
xpReward += 4;
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
getSpecialData().rangedAttackDamage += 2.0F;
|
||||
disableRangedAI();
|
||||
}
|
||||
public UnholyGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
protected void onVariantAttack( Entity target ) {
|
||||
|
@ -120,14 +107,4 @@ public class UnholyGhastEntity extends _SpecialGhastEntity {
|
|||
}
|
||||
super.aiStep();
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "unholy" ),
|
||||
null,
|
||||
GET_TEXTURE_PATH( "unholy_shooting" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.common.entity.ghast;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.ai.AIHelper;
|
||||
|
@ -32,7 +31,6 @@ import net.minecraft.network.datasync.DataSerializers;
|
|||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
|
@ -53,11 +51,14 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
public static MobFamily.Species<_SpecialGhastEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xBCBCBC );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xBCBCBC )
|
||||
.vanillaTextureWithAnimation( "textures/entity/ghast/ghast.png", "textures/entity/ghast/ghast_shooting.png" )
|
||||
.experience( 5 ).fireImmune()
|
||||
.fireballAttack( 0.0, 20, 40, 64.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return GhastEntity.createAttributes().add( Attributes.ATTACK_DAMAGE, 4.0 );
|
||||
}
|
||||
|
@ -79,13 +80,6 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
moveControl = new SimpleFlyingMovementController( this );
|
||||
reassessAttackGoal();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called in the MobEntity.class constructor to initialize AI goals. */
|
||||
@Override
|
||||
protected void registerGoals() {
|
||||
|
@ -94,24 +88,18 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
AIHelper.removeGoals( goalSelector, 7 ); // GhastEntity.LookAroundGoal & GhastEntity.FireballAttackGoal
|
||||
goalSelector.addGoal( 7, new SpecialGhastLookAroundGoal( this ) );
|
||||
|
||||
// Allow ghasts to target things not directly horizontal to them (why was this ever added?) TODO config
|
||||
AIHelper.removeGoals( targetSelector, NearestAttackableTargetGoal.class );
|
||||
targetSelector.addGoal( 1, new NearestAttackableTargetGoal<>( this, PlayerEntity.class, true ) );
|
||||
// Allow ghasts to target things not directly horizontal to them (why was this ever added?)
|
||||
if( MobFamily.GHAST.config.GHASTS.allowVerticalTargeting.get() ) {
|
||||
AIHelper.removeGoals( targetSelector, NearestAttackableTargetGoal.class );
|
||||
targetSelector.addGoal( 1, new NearestAttackableTargetGoal<>( this, PlayerEntity.class, true ) );
|
||||
}
|
||||
|
||||
getSpecialData().rangedAttackDamage = 2.0F;
|
||||
getSpecialData().rangedAttackSpread = 0.0F;
|
||||
getSpecialData().rangedAttackCooldown = 20;
|
||||
getSpecialData().rangedAttackMaxCooldown = 60;
|
||||
getSpecialData().rangedAttackMaxRange = 64.0F;
|
||||
registerVariantGoals();
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() { }
|
||||
|
||||
/** Helper method to set the ranged attack AI more easily. */
|
||||
protected void disableRangedAI() { getSpecialData().rangedAttackMaxRange = 0.0F; }
|
||||
|
||||
/** Override to change this entity's attack goal priority. */
|
||||
protected int getVariantAttackPriority() { return 4; }
|
||||
|
||||
|
@ -120,7 +108,7 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
public void performRangedAttack( LivingEntity target, float damageMulti ) {
|
||||
if( !isSilent() ) level.levelEvent( null, References.EVENT_GHAST_SHOOT, blockPosition(), 0 );
|
||||
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().rangedAttackSpread;
|
||||
final float accelVariance = MathHelper.sqrt( distanceTo( target ) ) * 0.5F * getSpecialData().getRangedAttackSpread();
|
||||
final Vector3d lookVec = getViewVector( 1.0F ).scale( getBbWidth() );
|
||||
double dX = target.getX() - (getX() + lookVec.x) + getRandom().nextGaussian() * accelVariance;
|
||||
double dY = target.getY( 0.5 ) - (0.5 + getY( 0.5 ));
|
||||
|
@ -163,11 +151,18 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
/** This entity's attack AI. */
|
||||
private Goal currentAttackAI;
|
||||
|
||||
public _SpecialGhastEntity( EntityType<? extends _SpecialGhastEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
moveControl = new SimpleFlyingMovementController( this );
|
||||
reassessAttackGoal();
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
}
|
||||
|
||||
/** Called on spawn to initialize properties based on the world, difficulty, and the group it spawns with. */
|
||||
|
@ -191,7 +186,7 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
if( level != null && !level.isClientSide ) {
|
||||
if( currentAttackAI != null ) goalSelector.removeGoal( currentAttackAI );
|
||||
|
||||
currentAttackAI = getSpecialData().rangedAttackMaxRange > 0.0F ?
|
||||
currentAttackAI = getSpecialData().getRangedAttackMaxRange() > 0.0F ?
|
||||
new SpecialGhastFireballAttackGoal( this ) :
|
||||
new SpecialGhastMeleeAttackGoal( this );
|
||||
|
||||
|
@ -208,6 +203,11 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
@Override
|
||||
public SpecialMobData<_SpecialGhastEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialGhastEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final int getExperience() { return xpReward; }
|
||||
|
@ -216,20 +216,6 @@ public class _SpecialGhastEntity extends GhastEntity implements IRangedAttackMob
|
|||
@Override
|
||||
public final void setExperience( int xp ) { xpReward = xp; }
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "ghast/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/ghast/ghast.png" ),
|
||||
null,
|
||||
new ResourceLocation( "textures/entity/ghast/ghast_shooting.png" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ 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.Attributes;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.Items;
|
||||
|
@ -19,7 +18,6 @@ import net.minecraft.nbt.CompoundNBT;
|
|||
import net.minecraft.pathfinding.PathNavigator;
|
||||
import net.minecraft.pathfinding.PathNodeType;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -35,10 +33,12 @@ public class BouncingMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
public static MobFamily.Species<BouncingMagmaCubeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.fireImmune();
|
||||
return new BestiaryInfo( 0xB333B3 );
|
||||
//TODO theme - mountain
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xB333B3 ).theme( BestiaryInfo.Theme.MOUNTAIN )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 1 ).fallImmune()
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 4.0 )
|
||||
.multiplyAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -56,24 +56,19 @@ public class BouncingMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<BouncingMagmaCubeEntity> getVariantFactory() { return BouncingMagmaCubeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends BouncingMagmaCubeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public BouncingMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setFallDamageMultiplier( 0.0F );
|
||||
slimeExperienceValue += 1;
|
||||
|
||||
setPathfindingMalus( PathNodeType.LAVA, PathNodeType.WALKABLE.getMalus() );
|
||||
}
|
||||
|
||||
/** Override to modify this slime's base attributes by size. */
|
||||
@Override
|
||||
protected void modifyVariantAttributes( int size ) {
|
||||
addAttribute( Attributes.MAX_HEALTH, 2.0 * size );
|
||||
multAttribute( Attributes.MOVEMENT_SPEED, 1.2 );
|
||||
}
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
protected void registerVariantGoals() {
|
||||
AIHelper.removeGoals( goalSelector, 1 ); // SlimeEntity.FloatGoal
|
||||
|
@ -104,12 +99,4 @@ public class BouncingMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
public void readVariantSaveData( CompoundNBT saveTag ) {
|
||||
setPathfindingMalus( PathNodeType.LAVA, PathNodeType.WALKABLE.getMalus() );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "bouncing" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -12,7 +12,6 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -29,9 +28,13 @@ public class HardenedMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
public static MobFamily.Species<HardenedMagmaCubeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
entityType.sized( 3.06F, 3.06F );
|
||||
return new BestiaryInfo( 0xDF7679, BestiaryInfo.BaseWeight.LOW );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xDF7679 ).weight( BestiaryInfo.DefaultWeight.LOW )
|
||||
.uniqueTextureBaseOnly()
|
||||
.size( 1.5F, 3.06F, 3.06F )
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 8.0 ).addToAttribute( Attributes.ARMOR, 16.0 )
|
||||
.addToAttribute( Attributes.ATTACK_DAMAGE, 1.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -49,21 +52,15 @@ public class HardenedMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<HardenedMagmaCubeEntity> getVariantFactory() { return HardenedMagmaCubeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends HardenedMagmaCubeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public HardenedMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().setBaseScale( 1.5F );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
/** 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 );
|
||||
addAttribute( Attributes.ARMOR, 8.0 );
|
||||
}
|
||||
public HardenedMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
|
@ -86,12 +83,4 @@ public class HardenedMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
setDeltaMovement( getDeltaMovement().multiply( 0.2, 1.0, 0.2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "hardened" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -12,7 +12,6 @@ import net.minecraft.entity.LivingEntity;
|
|||
import net.minecraft.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
@ -29,8 +28,11 @@ public class StickyMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
public static MobFamily.Species<StickyMagmaCubeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x9D733F );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x9D733F )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 8.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -48,23 +50,19 @@ public class StickyMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<StickyMagmaCubeEntity> getVariantFactory() { return StickyMagmaCubeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends StickyMagmaCubeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public StickyMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
public StickyMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to apply effects when this entity hits a target with a melee attack. */
|
||||
@Override
|
||||
|
@ -90,12 +88,4 @@ public class StickyMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "sticky" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
}
|
|
@ -3,15 +3,15 @@ package fathertoast.specialmobs.common.entity.magmacube;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.IExplodingMob;
|
||||
import fathertoast.specialmobs.common.entity.ai.goal.SpecialSwellGoal;
|
||||
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.Attributes;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
|
@ -21,19 +21,17 @@ 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 VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
||||
public class VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity implements IExplodingMob {
|
||||
|
||||
//--------------- Static Special Mob Hooks ----------------
|
||||
|
||||
|
@ -41,8 +39,11 @@ public class VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
public static MobFamily.Species<VolatileMagmaCubeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0x331133 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0x331133 )
|
||||
.uniqueTextureBaseOnly()
|
||||
.addExperience( 2 )
|
||||
.addToAttribute( Attributes.MAX_HEALTH, 2.0 );
|
||||
}
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
|
@ -60,39 +61,34 @@ public class VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
@SpecialMob.Factory
|
||||
public static EntityType.IFactory<VolatileMagmaCubeEntity> getVariantFactory() { return VolatileMagmaCubeEntity::new; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends VolatileMagmaCubeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
|
||||
//--------------- Variant-Specific Implementations ----------------
|
||||
|
||||
public VolatileMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
slimeExperienceValue += 2;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
public VolatileMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) { super( entityType, world ); }
|
||||
|
||||
/** Override to change this entity's AI goals. */
|
||||
@Override
|
||||
protected void registerVariantGoals() {
|
||||
goalSelector.addGoal( 0, new SlimeSwellGoal( this ) );
|
||||
goalSelector.addGoal( 0, new SpecialSwellGoal<>( this ) );
|
||||
}
|
||||
|
||||
/** Called each tick to update this entity. */
|
||||
@Override
|
||||
public void tick() {
|
||||
if( isAlive() && !level.isClientSide() ) {
|
||||
if( ignited ) swellDir = 1;
|
||||
if( ignited ) setSwellDir( 1 );
|
||||
|
||||
if( swellDir > 0 ) {
|
||||
if( getSwellDir() > 0 ) {
|
||||
if( fuse == 0 ) {
|
||||
playSound( SoundEvents.CREEPER_PRIMED, 1.0F, 0.5F );
|
||||
}
|
||||
|
@ -106,9 +102,9 @@ public class VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
changeFuse( +1 );
|
||||
}
|
||||
}
|
||||
else if( swellDir < 0 && fuse > 0 ) {
|
||||
else if( getSwellDir() < 0 && fuse > 0 ) {
|
||||
changeFuse( -1 );
|
||||
if( fuse <= 0 ) swellDir = 0;
|
||||
if( fuse <= 0 ) setSwellDir( 0 );
|
||||
}
|
||||
}
|
||||
super.tick();
|
||||
|
@ -187,51 +183,20 @@ public class VolatileMagmaCubeEntity extends _SpecialMagmaCubeEntity {
|
|||
@Override
|
||||
protected IParticleData getParticleType() { return ParticleTypes.SMOKE; }
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
GET_TEXTURE_PATH( "volatile" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
//--------------- IExplodingEntity Implementations ----------------
|
||||
|
||||
private int swellDir = 0;
|
||||
|
||||
/** Sets this exploding entity's swell direction. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
public void setSwellDir( int value ) { swellDir = value; }
|
||||
|
||||
/** @return This exploding entity's swell direction. */
|
||||
@Override
|
||||
public int getSwellDir() { return swellDir; }
|
||||
|
||||
//--------------- Nested Classes ----------------
|
||||
|
||||
/** The "creeper swell" goal repurposed for use on a slime. */
|
||||
private static class SlimeSwellGoal extends Goal {
|
||||
|
||||
private final VolatileMagmaCubeEntity slime;
|
||||
|
||||
private LivingEntity target;
|
||||
|
||||
public SlimeSwellGoal( VolatileMagmaCubeEntity 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @return Additional range from its target at which this entity will start to explode. */
|
||||
@Override
|
||||
public double getExtraRange() { return (getSize() - 1) * 2.0F; }
|
||||
}
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.common.entity.magmacube;
|
|||
import fathertoast.specialmobs.common.bestiary.BestiaryInfo;
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.bestiary.SpecialMob;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
|
@ -11,20 +10,18 @@ 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.AttributeModifierManager;
|
||||
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.MagmaCubeEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.projectile.SnowballEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
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.World;
|
||||
|
||||
|
@ -41,11 +38,13 @@ public class _SpecialMagmaCubeEntity extends MagmaCubeEntity implements ISpecial
|
|||
public static MobFamily.Species<_SpecialMagmaCubeEntity> SPECIES;
|
||||
|
||||
@SpecialMob.BestiaryInfoSupplier
|
||||
public static BestiaryInfo bestiaryInfo( EntityType.Builder<LivingEntity> entityType ) {
|
||||
return new BestiaryInfo( 0xFCFC00 );
|
||||
public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) {
|
||||
bestiaryInfo.color( 0xFCFC00 )
|
||||
.vanillaTextureBaseOnly( "textures/entity/slime/magmacube.png" )
|
||||
.experience( 0 );
|
||||
}
|
||||
|
||||
@SpecialMob.AttributeCreator
|
||||
@SpecialMob.AttributeSupplier
|
||||
public static AttributeModifierMap.MutableAttribute createAttributes() {
|
||||
return MagmaCubeEntity.createAttributes(); // Slimes define their attributes elsewhere based on size
|
||||
}
|
||||
|
@ -67,14 +66,6 @@ public class _SpecialMagmaCubeEntity extends MagmaCubeEntity implements ISpecial
|
|||
|
||||
//--------------- Variant-Specific Breakouts ----------------
|
||||
|
||||
public _SpecialMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** 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() {
|
||||
|
@ -107,62 +98,39 @@ public class _SpecialMagmaCubeEntity extends MagmaCubeEntity implements ISpecial
|
|||
/** The parameter for special mob render scale. */
|
||||
private static final DataParameter<Float> SCALE = EntityDataManager.defineId( _SpecialMagmaCubeEntity.class, DataSerializers.FLOAT );
|
||||
|
||||
protected int slimeExperienceValue = 0;
|
||||
/** Used to reset slimes' attributes to their freshly spawned state so attribute adjustments may be reapplied on size change. */
|
||||
private static ListNBT magmaCubeAttributeSnapshot;
|
||||
|
||||
private static ListNBT getAttributeSnapshot() {
|
||||
if( magmaCubeAttributeSnapshot == null )
|
||||
magmaCubeAttributeSnapshot = new AttributeModifierManager( createAttributes().build() ).save();
|
||||
return magmaCubeAttributeSnapshot;
|
||||
}
|
||||
|
||||
private int slimeExperienceValue = 0;
|
||||
|
||||
public _SpecialMagmaCubeEntity( EntityType<? extends _SpecialMagmaCubeEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
getSpecialData().initialize();
|
||||
}
|
||||
|
||||
/** Called from the Entity.class constructor to define data watcher variables. */
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
specialData = new SpecialMobData<>( this, SCALE, 1.0F );
|
||||
specialData = new SpecialMobData<>( this, SCALE );
|
||||
}
|
||||
|
||||
/** Sets this slime's size, optionally resetting its health to max. */
|
||||
@Override
|
||||
protected void setSize( int size, boolean resetHealth ) {
|
||||
// We must reset all attributes and reapply changes since slimes set attribute base values on size change
|
||||
getAttributes().load( getAttributeSnapshot() );
|
||||
super.setSize( size, resetHealth );
|
||||
getSpecies().config.GENERAL.attributeChanges.apply( this );
|
||||
|
||||
modifyVariantAttributes( size );
|
||||
if( resetHealth ) setHealth( getMaxHealth() );
|
||||
xpReward = size + slimeExperienceValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters this magma cube'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.ARMOR && attribute != Attributes.ATTACK_DAMAGE && attribute != Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Magma cube relative attributes are only health, armor, 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 magma cube'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.ARMOR && attribute != Attributes.ATTACK_DAMAGE && attribute != Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Magma cube relative attributes are only health, armor, 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 magma cube's base attribute. */
|
||||
protected void setAttribute( Attribute attribute, double amount ) {
|
||||
if( attribute == Attributes.MAX_HEALTH || attribute == Attributes.ARMOR || attribute == Attributes.ATTACK_DAMAGE || attribute == Attributes.MOVEMENT_SPEED )
|
||||
throw new IllegalArgumentException( "Use magma cube relative attribute!" );
|
||||
|
||||
final ModifiableAttributeInstance attributeInstance = getAttribute( attribute );
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + attribute.getDescriptionId() );
|
||||
attributeInstance.setBaseValue( amount );
|
||||
setExperience( getExperience() ); // Update for new size
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,6 +142,11 @@ public class _SpecialMagmaCubeEntity extends MagmaCubeEntity implements ISpecial
|
|||
@Override
|
||||
public SpecialMobData<_SpecialMagmaCubeEntity> getSpecialData() { return specialData; }
|
||||
|
||||
/** @return This entity's mob species. */
|
||||
@SpecialMob.SpeciesSupplier
|
||||
@Override
|
||||
public MobFamily.Species<? extends _SpecialMagmaCubeEntity> getSpecies() { return SPECIES; }
|
||||
|
||||
/** @return The experience that should be dropped by this entity. */
|
||||
@Override
|
||||
public final int getExperience() { return slimeExperienceValue; } // Slime base xp
|
||||
|
@ -185,18 +158,6 @@ public class _SpecialMagmaCubeEntity extends MagmaCubeEntity implements ISpecial
|
|||
xpReward = getSize() + xp;
|
||||
}
|
||||
|
||||
static ResourceLocation GET_TEXTURE_PATH( String type ) {
|
||||
return SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "magmacube/" + type + ".png" );
|
||||
}
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = {
|
||||
new ResourceLocation( "textures/entity/slime/magmacube.png" )
|
||||
};
|
||||
|
||||
/** @return All default textures for this entity. */
|
||||
@Override
|
||||
public ResourceLocation[] getDefaultTextures() { return TEXTURES; }
|
||||
|
||||
|
||||
//--------------- SpecialMobData Hooks ----------------
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ import fathertoast.specialmobs.common.core.register.SMEntities;
|
|||
import fathertoast.specialmobs.common.core.register.SMItems;
|
||||
import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.projectile.AbstractFireballEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
|
@ -31,177 +31,180 @@ import net.minecraftforge.event.ForgeEventFactory;
|
|||
import net.minecraftforge.fml.network.NetworkHooks;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
public class CorporealShiftFireballEntity extends AbstractFireballEntity {
|
||||
|
||||
private static final DataParameter<Boolean> CORPOREAL = EntityDataManager.defineId(CorporealShiftFireballEntity.class, DataSerializers.BOOLEAN);
|
||||
|
||||
|
||||
private static final DataParameter<Boolean> CORPOREAL = EntityDataManager.defineId( CorporealShiftFireballEntity.class, DataSerializers.BOOLEAN );
|
||||
|
||||
public int explosionPower = 1;
|
||||
private boolean shouldExplode = false;
|
||||
|
||||
|
||||
@Nullable
|
||||
private LivingEntity target;
|
||||
|
||||
|
||||
public CorporealShiftFireballEntity(EntityType<? extends AbstractFireballEntity> entityType, World world) {
|
||||
super(entityType, world);
|
||||
|
||||
|
||||
public CorporealShiftFireballEntity( EntityType<? extends AbstractFireballEntity> entityType, World world ) {
|
||||
super( entityType, world );
|
||||
}
|
||||
|
||||
public CorporealShiftFireballEntity(World world, CorporealShiftGhastEntity ghast, double x, double y, double z) {
|
||||
super(SMEntities.CORPOREAL_FIREBALL.get(), ghast, x, y, z, world);
|
||||
setCorporeal(ghast.isCorporeal());
|
||||
|
||||
public CorporealShiftFireballEntity( World world, CorporealShiftGhastEntity ghast, double x, double y, double z ) {
|
||||
super( SMEntities.CORPOREAL_FIREBALL.get(), ghast, x, y, z, world );
|
||||
setCorporeal( ghast.isCorporeal() );
|
||||
target = ghast.getTarget();
|
||||
setItem(isCorporeal() ? new ItemStack(Items.FIRE_CHARGE) : new ItemStack(SMItems.INCORPOREAL_FIREBALL.get()));
|
||||
setItem( isCorporeal() ? new ItemStack( Items.FIRE_CHARGE ) : new ItemStack( SMItems.INCORPOREAL_FIREBALL.get() ) );
|
||||
}
|
||||
|
||||
public CorporealShiftFireballEntity(World world, PlayerEntity owner, LivingEntity target, double x, double y, double z) {
|
||||
super(SMEntities.CORPOREAL_FIREBALL.get(), owner, x, y, z, world);
|
||||
setCorporeal(false);
|
||||
|
||||
public CorporealShiftFireballEntity( World world, PlayerEntity owner, LivingEntity target, double x, double y, double z ) {
|
||||
super( SMEntities.CORPOREAL_FIREBALL.get(), owner, x, y, z, world );
|
||||
setCorporeal( false );
|
||||
this.target = target;
|
||||
setItem(new ItemStack(SMItems.INCORPOREAL_FIREBALL.get()));
|
||||
setItem( new ItemStack( SMItems.INCORPOREAL_FIREBALL.get() ) );
|
||||
}
|
||||
|
||||
|
||||
@SpecialMob.LanguageProvider
|
||||
public static String[] getTranslations( String langKey ) {
|
||||
return References.translations( langKey, "Corporeal Shift Fireball",
|
||||
"", "", "", "", "", "" );//TODO
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData() {
|
||||
super.defineSynchedData();
|
||||
entityData.define(CORPOREAL, true);
|
||||
entityData.define( CORPOREAL, true );
|
||||
}
|
||||
|
||||
|
||||
public boolean isCorporeal() {
|
||||
return entityData.get(CORPOREAL);
|
||||
return entityData.get( CORPOREAL );
|
||||
}
|
||||
|
||||
public void setCorporeal(boolean corporeal) {
|
||||
entityData.set(CORPOREAL, corporeal);
|
||||
|
||||
public void setCorporeal( boolean corporeal ) {
|
||||
entityData.set( CORPOREAL, corporeal );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if ( !level.isClientSide && !isCorporeal() ) {
|
||||
|
||||
if( !level.isClientSide && !isCorporeal() ) {
|
||||
// Fizzle out and die when the target is dead or lost,
|
||||
// or else the fireball goes bonkers.
|
||||
if ( target == null || !target.isAlive() ) {
|
||||
playSound(SoundEvents.FIRE_EXTINGUISH, 1.0F, 1.0F);
|
||||
if( target == null || !target.isAlive() ) {
|
||||
playSound( SoundEvents.FIRE_EXTINGUISH, 1.0F, 1.0F );
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
// Follow target
|
||||
Vector3d vector3d = new Vector3d( target.getX() - this.getX(), (target.getY() + (target.getEyeHeight() / 2)) - this.getY(), target.getZ() - this.getZ() );
|
||||
setDeltaMovement(vector3d.normalize().scale(0.5));
|
||||
setDeltaMovement( vector3d.normalize().scale( 0.5 ) );
|
||||
}
|
||||
|
||||
if ( !level.isClientSide && shouldExplode )
|
||||
|
||||
if( !level.isClientSide && shouldExplode )
|
||||
explode();
|
||||
}
|
||||
|
||||
|
||||
private void explode() {
|
||||
boolean mobGrief = ForgeEventFactory.getMobGriefingEvent( level, getOwner() );
|
||||
Explosion.Mode mode = mobGrief ? Explosion.Mode.DESTROY : Explosion.Mode.NONE;
|
||||
|
||||
level.explode( null, this.getX(), this.getY(), this.getZ(), (float)explosionPower, mobGrief, mode );
|
||||
|
||||
level.explode( null, this.getX(), this.getY(), this.getZ(), (float) explosionPower, mobGrief, mode );
|
||||
target = null;
|
||||
remove();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean shouldBurn() {
|
||||
// Hee hee hee haw
|
||||
return isCorporeal();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onHit( RayTraceResult traceResult ) {
|
||||
super.onHit( traceResult );
|
||||
|
||||
|
||||
// Only go boom if the fireball is corporeal.
|
||||
// If not, pass through blocks to be a menace.
|
||||
if ( !level.isClientSide && isCorporeal() ) {
|
||||
if( !level.isClientSide && isCorporeal() ) {
|
||||
shouldExplode = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onHitEntity( EntityRayTraceResult traceResult ) {
|
||||
super.onHitEntity(traceResult);
|
||||
|
||||
if ( !this.level.isClientSide ) {
|
||||
super.onHitEntity( traceResult );
|
||||
|
||||
if( !this.level.isClientSide ) {
|
||||
Entity target = traceResult.getEntity();
|
||||
Entity owner = getOwner();
|
||||
|
||||
if (!isCorporeal()) {
|
||||
|
||||
if( !isCorporeal() ) {
|
||||
// TODO - Figure out why this is cringe
|
||||
// TODO part 2. - What the fuck
|
||||
// TODO part 3. - HELP
|
||||
SpecialMobs.LOG.info("X={}, XO={}", target.getX(), target.xo);
|
||||
SpecialMobs.LOG.info("Z={}, ZO={}", target.getZ(), target.zo);
|
||||
|
||||
if (target.getX() != target.xo || target.getY() != target.yo || target.getZ() != target.zo) {
|
||||
SpecialMobs.LOG.info( "X={}, XO={}", target.getX(), target.xo );
|
||||
SpecialMobs.LOG.info( "Z={}, ZO={}", target.getZ(), target.zo );
|
||||
|
||||
if( target.getX() != target.xo || target.getY() != target.yo || target.getZ() != target.zo ) {
|
||||
explode();
|
||||
}
|
||||
else {
|
||||
playSound(SoundEvents.FIRE_EXTINGUISH, 1.0F, 1.0F);
|
||||
playSound( SoundEvents.FIRE_EXTINGUISH, 1.0F, 1.0F );
|
||||
remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
target.hurt(DamageSource.fireball(this, owner), 6.0F);
|
||||
|
||||
if (owner instanceof LivingEntity) {
|
||||
doEnchantDamageEffects((LivingEntity) owner, target);
|
||||
target.hurt( DamageSource.fireball( this, owner ), 6.0F );
|
||||
|
||||
if( owner instanceof LivingEntity ) {
|
||||
doEnchantDamageEffects( (LivingEntity) owner, target );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hurt(DamageSource damageSource, float damage) {
|
||||
if (!isCorporeal()) {
|
||||
if (isInvulnerableTo(damageSource) || damageSource.isFire()) {
|
||||
public boolean hurt( DamageSource damageSource, float damage ) {
|
||||
if( !isCorporeal() ) {
|
||||
if( isInvulnerableTo( damageSource ) || damageSource.isFire() ) {
|
||||
return false;
|
||||
}
|
||||
shouldExplode = true;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return super.hurt(damageSource, damage);
|
||||
return super.hurt( damageSource, damage );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(CompoundNBT compoundNBT) {
|
||||
super.addAdditionalSaveData(compoundNBT);
|
||||
compoundNBT.putInt("ExplosionPower", explosionPower);
|
||||
compoundNBT.putBoolean("Corporeal", isCorporeal());
|
||||
compoundNBT.putInt("TargetId", target == null ? -1 : target.getId());
|
||||
public void addAdditionalSaveData( CompoundNBT compoundNBT ) {
|
||||
super.addAdditionalSaveData( compoundNBT );
|
||||
compoundNBT.putInt( "ExplosionPower", explosionPower );
|
||||
compoundNBT.putBoolean( "Corporeal", isCorporeal() );
|
||||
compoundNBT.putInt( "TargetId", target == null ? -1 : target.getId() );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void readAdditionalSaveData(CompoundNBT compoundNBT) {
|
||||
super.readAdditionalSaveData(compoundNBT);
|
||||
if (compoundNBT.contains("ExplosionPower", Constants.NBT.TAG_ANY_NUMERIC)) {
|
||||
explosionPower = compoundNBT.getInt("ExplosionPower");
|
||||
public void readAdditionalSaveData( CompoundNBT compoundNBT ) {
|
||||
super.readAdditionalSaveData( compoundNBT );
|
||||
if( compoundNBT.contains( "ExplosionPower", Constants.NBT.TAG_ANY_NUMERIC ) ) {
|
||||
explosionPower = compoundNBT.getInt( "ExplosionPower" );
|
||||
}
|
||||
entityData.set(CORPOREAL, compoundNBT.getBoolean("Corporeal"));
|
||||
|
||||
if (compoundNBT.contains("TargetId", Constants.NBT.TAG_ANY_NUMERIC)) {
|
||||
Entity entity = level.getEntity(compoundNBT.getInt("TargetId"));
|
||||
|
||||
if (entity instanceof LivingEntity) {
|
||||
entityData.set( CORPOREAL, compoundNBT.getBoolean( "Corporeal" ) );
|
||||
|
||||
if( compoundNBT.contains( "TargetId", Constants.NBT.TAG_ANY_NUMERIC ) ) {
|
||||
Entity entity = level.getEntity( compoundNBT.getInt( "TargetId" ) );
|
||||
|
||||
if( entity instanceof LivingEntity ) {
|
||||
target = (LivingEntity) entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IPacket<?> getAddEntityPacket() {
|
||||
return NetworkHooks.getEntitySpawningPacket(this);
|
||||
return NetworkHooks.getEntitySpawningPacket( this );
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue