From 9eccaed1a98d48775c7fad5df3775a17fa1c7d0b Mon Sep 17 00:00:00 2001 From: FatherToast Date: Wed, 13 Jul 2022 10:31:37 -0500 Subject: [PATCH] MADMAN (also some other stuff) --- .../specialmobs/client/ClientRegister.java | 2 + .../entity/CorporealShiftGhastRenderer.java | 44 ++++++++----- .../entity/SpecialZombieVillagerRenderer.java | 48 ++++++++++++++ .../common/bestiary/MobFamily.java | 8 +-- .../config/family/CreeperFamilyConfig.java | 2 +- .../common/config/family/FamilyConfig.java | 13 ++-- .../config/family/SilverfishFamilyConfig.java | 2 +- .../config/family/SlimeFamilyConfig.java | 2 +- .../MadScientistZombieSpeciesConfig.java | 35 ++++++++++ .../common/entity/ai/IAmmoUser.java | 13 ++++ .../entity/ai/goal/ChargeCreeperGoal.java | 20 ++++-- .../zombie/MadScientistZombieEntity.java | 65 +++++++++++++++++-- .../specialmobs/common/util/References.java | 4 +- 13 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 src/main/java/fathertoast/specialmobs/client/renderer/entity/SpecialZombieVillagerRenderer.java create mode 100644 src/main/java/fathertoast/specialmobs/common/config/species/MadScientistZombieSpeciesConfig.java create mode 100644 src/main/java/fathertoast/specialmobs/common/entity/ai/IAmmoUser.java diff --git a/src/main/java/fathertoast/specialmobs/client/ClientRegister.java b/src/main/java/fathertoast/specialmobs/client/ClientRegister.java index 9a22b61..1b9eb2b 100644 --- a/src/main/java/fathertoast/specialmobs/client/ClientRegister.java +++ b/src/main/java/fathertoast/specialmobs/client/ClientRegister.java @@ -7,6 +7,7 @@ import fathertoast.specialmobs.common.core.register.SMEntities; import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity; import fathertoast.specialmobs.common.entity.skeleton.NinjaSkeletonEntity; import fathertoast.specialmobs.common.entity.witherskeleton.NinjaWitherSkeletonEntity; +import fathertoast.specialmobs.common.entity.zombie.MadScientistZombieEntity; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ItemRenderer; @@ -54,6 +55,7 @@ public class ClientRegister { registerFamilyRenderers( MobFamily.BLAZE, SpecialBlazeRenderer::new ); // Species overrides + registerSpeciesRenderer( MadScientistZombieEntity.SPECIES, SpecialZombieVillagerRenderer::new ); registerSpeciesRenderer( NinjaSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new ); registerSpeciesRenderer( NinjaWitherSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new ); registerSpeciesRenderer( CorporealShiftGhastEntity.SPECIES, CorporealShiftGhastRenderer::new ); diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java index eb355e6..bb94edf 100644 --- a/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java @@ -7,46 +7,54 @@ import fathertoast.specialmobs.common.core.SpecialMobs; import fathertoast.specialmobs.common.entity.ISpecialMob; import fathertoast.specialmobs.common.entity.SpecialMobData; import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity; +import mcp.MethodsReturnNonnullByDefault; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.MobRenderer; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import javax.annotation.ParametersAreNonnullByDefault; import java.util.function.Function; +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@OnlyIn( Dist.CLIENT ) public class CorporealShiftGhastRenderer extends MobRenderer> { - - private static final Function INCORPOREAL = (resourceLocation) -> SMRenderTypes.entityCutoutNoCullBlend(resourceLocation, SMRenderTypes.INCORPOREAL_ALPHA); - - private static final ResourceLocation EYES = SpecialMobs.resourceLoc("textures/entity/ghast/corporeal_shift_eyes.png"); - private static final ResourceLocation SHOOT_EYES = SpecialMobs.resourceLoc("textures/entity/ghast/corporeal_shift_shoot_eyes.png"); - + + private static final Function INCORPOREAL = ( resourceLocation ) -> SMRenderTypes.entityCutoutNoCullBlend( resourceLocation, SMRenderTypes.INCORPOREAL_ALPHA ); + + private static final ResourceLocation EYES = SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "ghast/corporeal_shift_eyes.png" ); + private static final ResourceLocation SHOOT_EYES = SpecialMobs.resourceLoc( SpecialMobs.TEXTURE_PATH + "ghast/corporeal_shift_shooting_eyes.png" ); + private final float baseShadowRadius; - - public CorporealShiftGhastRenderer(EntityRendererManager rendererManager) { - super(rendererManager, new CorporealShiftGhastModel<>(), 1.5F); - addLayer(new SpecialGhastEyesLayer<>(this, EYES, SHOOT_EYES )); + + public CorporealShiftGhastRenderer( EntityRendererManager rendererManager ) { + super( rendererManager, new CorporealShiftGhastModel<>(), 1.5F ); + addLayer( new SpecialGhastEyesLayer<>( this, EYES, SHOOT_EYES ) ); baseShadowRadius = shadowRadius; } - + @Override - public void render(CorporealShiftGhastEntity ghast, float rotation, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) { + public void render( CorporealShiftGhastEntity ghast, float rotation, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight ) { model.renderType = ghast.isCorporeal() ? RenderType::entityCutoutNoCull : INCORPOREAL; - super.render(ghast, rotation, partialTicks, matrixStack, buffer, packedLight); + super.render( ghast, rotation, partialTicks, matrixStack, buffer, packedLight ); } - - + + @Override public ResourceLocation getTextureLocation( CorporealShiftGhastEntity entity ) { final SpecialMobData data = ((ISpecialMob) entity).getSpecialData(); return entity.isCharging() && data.hasOverlayTexture() ? data.getTextureOverlay() : data.getTexture(); } - + @Override protected void scale( CorporealShiftGhastEntity entity, MatrixStack matrixStack, float partialTick ) { - final float scale = 4.5F + ((ISpecialMob) entity).getSpecialData().getRenderScale(); + // The base scale of 4.5 is taken from GhastRenderer + final float scale = 4.5F * ((ISpecialMob) entity).getSpecialData().getRenderScale(); shadowRadius = baseShadowRadius * scale; matrixStack.scale( scale, scale, scale ); } -} +} \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/SpecialZombieVillagerRenderer.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/SpecialZombieVillagerRenderer.java new file mode 100644 index 0000000..1c3d7a6 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/SpecialZombieVillagerRenderer.java @@ -0,0 +1,48 @@ +package fathertoast.specialmobs.client.renderer.entity; + +import com.mojang.blaze3d.matrix.MatrixStack; +import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer; +import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer; +import fathertoast.specialmobs.common.entity.ISpecialMob; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.client.renderer.entity.BipedRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.client.renderer.entity.layers.BipedArmorLayer; +import net.minecraft.client.renderer.entity.model.ZombieVillagerModel; +import net.minecraft.entity.monster.ZombieEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@OnlyIn( Dist.CLIENT ) +public class SpecialZombieVillagerRenderer extends BipedRenderer> { + + private final float baseShadowRadius; + + public SpecialZombieVillagerRenderer( EntityRendererManager rendererManager ) { + super( rendererManager, new ZombieVillagerModel<>( 0.0F, false ), 0.5F ); + addLayer( new BipedArmorLayer<>( this, new ZombieVillagerModel<>( 0.5F, true ), new ZombieVillagerModel<>( 1.0F, true ) ) ); + + baseShadowRadius = shadowRadius; + addLayer( new SpecialMobEyesLayer<>( this ) ); + addLayer( new SpecialMobOverlayLayer<>( this, new ZombieVillagerModel<>( 0.25F, true ) ) ); + } + + @Override + public ResourceLocation getTextureLocation( ZombieEntity entity ) { + return ((ISpecialMob) entity).getSpecialData().getTexture(); + } + + @Override + protected void scale( ZombieEntity entity, MatrixStack matrixStack, float partialTick ) { + super.scale( entity, matrixStack, partialTick ); + + final float scale = ((ISpecialMob) entity).getSpecialData().getRenderScale(); + shadowRadius = baseShadowRadius * scale; + matrixStack.scale( scale, scale, scale ); + } +} \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java b/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java index fd4f705..c19b792 100644 --- a/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java +++ b/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java @@ -47,7 +47,7 @@ public class MobFamily { "Mini", /*"Scope",*/ "Skeleton", "Splitting" ); - public static final MobFamily ZOMBIE = new MobFamily<>( FamilyConfig::new, + public static final MobFamily ZOMBIE = new MobFamily<>( FamilyConfig::newLessSpecial, "Zombie", "zombies", 0x00AFAF, new EntityType[] { EntityType.ZOMBIE, EntityType.HUSK }, "Brute", "Fire", /*"Fishing",*/ "Giant", "Hungry", "Husk", "MadScientist", "Plague" ); @@ -70,16 +70,16 @@ public class MobFamily { "Slime", "slimes", 0x51A03E, new EntityType[] { EntityType.SLIME }, "Blackberry", "Blueberry", "Caramel", "Grape", "Lemon", "Strawberry", "Watermelon" ); - public static final MobFamily MAGMA_CUBE = new MobFamily<>( FamilyConfig::new, + public static final MobFamily MAGMA_CUBE = new MobFamily<>( FamilyConfig::newMoreSpecial, "MagmaCube", "magma cubes", 0x340000, new EntityType[] { EntityType.MAGMA_CUBE }, "Bouncing", "Hardened", "Sticky", "Volatile" ); - public static final MobFamily SPIDER = new MobFamily<>( FamilyConfig.withVariantChance( 0.33 ), + public static final MobFamily SPIDER = new MobFamily<>( FamilyConfig::newMoreSpecial, "Spider", "spiders", 0x342D27, new EntityType[] { EntityType.SPIDER }, "Baby", "Desert", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", /*"Water",*/ "Web", "Witch" ); - public static final MobFamily CAVE_SPIDER = new MobFamily<>( FamilyConfig.withVariantChance( 0.33 ), + public static final MobFamily CAVE_SPIDER = new MobFamily<>( FamilyConfig::newMoreSpecial, "CaveSpider", "cave spiders", 0x0C424E, new EntityType[] { EntityType.CAVE_SPIDER }, "Baby", "Flying", "Mother", /*"Water",*/ "Web", "Witch" ); diff --git a/src/main/java/fathertoast/specialmobs/common/config/family/CreeperFamilyConfig.java b/src/main/java/fathertoast/specialmobs/common/config/family/CreeperFamilyConfig.java index 79d4307..247ca06 100644 --- a/src/main/java/fathertoast/specialmobs/common/config/family/CreeperFamilyConfig.java +++ b/src/main/java/fathertoast/specialmobs/common/config/family/CreeperFamilyConfig.java @@ -15,7 +15,7 @@ public class CreeperFamilyConfig extends FamilyConfig { /** Builds the config spec that should be used for this config. */ public CreeperFamilyConfig( MobFamily family ) { - super( family, 0.33 ); + super( family, VARIANT_CHANCE_HIGH ); CREEPERS = new Creepers( SPEC, family ); } diff --git a/src/main/java/fathertoast/specialmobs/common/config/family/FamilyConfig.java b/src/main/java/fathertoast/specialmobs/common/config/family/FamilyConfig.java index 58eae7e..95939bd 100644 --- a/src/main/java/fathertoast/specialmobs/common/config/family/FamilyConfig.java +++ b/src/main/java/fathertoast/specialmobs/common/config/family/FamilyConfig.java @@ -11,21 +11,24 @@ import fathertoast.specialmobs.common.config.util.ConfigUtil; import java.io.File; import java.util.List; -import java.util.function.Function; /** * 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 { + protected static final double VARIANT_CHANCE_LOW = 0.2; + protected static final double VARIANT_CHANCE_HIGH = 0.33; + 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 ); } - /** @return A basic config supplier with custom default variant chance. */ - public static Function, FamilyConfig> withVariantChance( double chance ) { - return ( family ) -> new FamilyConfig( family, chance ); - } + /** @return A basic config supplier with a lower default variant chance. */ + public static FamilyConfig newLessSpecial( MobFamily family ) { return new FamilyConfig( family, VARIANT_CHANCE_LOW ); } + + /** @return A basic config supplier with a higher default variant chance. */ + public static FamilyConfig newMoreSpecial( MobFamily family ) { return new FamilyConfig( family, VARIANT_CHANCE_HIGH ); } /** Category containing all options applicable to mob families as a whole; i.e. not specific to any particular family. */ public final General GENERAL; diff --git a/src/main/java/fathertoast/specialmobs/common/config/family/SilverfishFamilyConfig.java b/src/main/java/fathertoast/specialmobs/common/config/family/SilverfishFamilyConfig.java index c824358..514955f 100644 --- a/src/main/java/fathertoast/specialmobs/common/config/family/SilverfishFamilyConfig.java +++ b/src/main/java/fathertoast/specialmobs/common/config/family/SilverfishFamilyConfig.java @@ -15,7 +15,7 @@ public class SilverfishFamilyConfig extends FamilyConfig { /** Builds the config spec that should be used for this config. */ public SilverfishFamilyConfig( MobFamily family ) { - super( family ); + super( family, VARIANT_CHANCE_LOW ); SILVERFISH = new Silverfish( SPEC, family ); } diff --git a/src/main/java/fathertoast/specialmobs/common/config/family/SlimeFamilyConfig.java b/src/main/java/fathertoast/specialmobs/common/config/family/SlimeFamilyConfig.java index 329a56f..8b6cca9 100644 --- a/src/main/java/fathertoast/specialmobs/common/config/family/SlimeFamilyConfig.java +++ b/src/main/java/fathertoast/specialmobs/common/config/family/SlimeFamilyConfig.java @@ -15,7 +15,7 @@ public class SlimeFamilyConfig extends FamilyConfig { /** Builds the config spec that should be used for this config. */ public SlimeFamilyConfig( MobFamily family ) { - super( family ); + super( family, VARIANT_CHANCE_HIGH ); SLIMES = new Slimes( SPEC, family ); } diff --git a/src/main/java/fathertoast/specialmobs/common/config/species/MadScientistZombieSpeciesConfig.java b/src/main/java/fathertoast/specialmobs/common/config/species/MadScientistZombieSpeciesConfig.java new file mode 100644 index 0000000..228ce89 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/common/config/species/MadScientistZombieSpeciesConfig.java @@ -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 MadScientistZombieSpeciesConfig extends ZombieSpeciesConfig { + + public final MadScientist MAD_SCIENTIST; + + /** Builds the config spec that should be used for this config. */ + public MadScientistZombieSpeciesConfig( MobFamily.Species species, double bowChance, double shieldChance, int minCharges, int maxCharges ) { + super( species, bowChance, shieldChance ); + + MAD_SCIENTIST = new MadScientist( SPEC, species, speciesName, minCharges, maxCharges ); + } + + public static class MadScientist extends Config.AbstractCategory { + + public final IntField.RandomRange chargeCount; + + MadScientist( ToastConfigSpec parent, MobFamily.Species species, String speciesName, int minCharges, int maxCharges ) { + super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ), + "Options specific to " + speciesName + "." ); + + chargeCount = new IntField.RandomRange( + SPEC.define( new IntField( "charges.min", minCharges, IntField.Range.NON_NEGATIVE, + "The minimum and maximum (inclusive) number of creepers a " + speciesName + " can charge." ) ), + SPEC.define( new IntField( "charges.max", maxCharges, IntField.Range.NON_NEGATIVE ) ) + ); + } + } +} \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/common/entity/ai/IAmmoUser.java b/src/main/java/fathertoast/specialmobs/common/entity/ai/IAmmoUser.java new file mode 100644 index 0000000..1d78769 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/common/entity/ai/IAmmoUser.java @@ -0,0 +1,13 @@ +package fathertoast.specialmobs.common.entity.ai; + +/** + * Monsters must implement this interface to use ammo-based AI goals. + * The default implementation is "unlimited ammo". + */ +public interface IAmmoUser { + /** @return True if this entity has ammo to use. */ + default boolean hasAmmo() { return true; } + + /** Consumes ammo for a single use. */ + default void consumeAmmo() { } +} \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/common/entity/ai/goal/ChargeCreeperGoal.java b/src/main/java/fathertoast/specialmobs/common/entity/ai/goal/ChargeCreeperGoal.java index dd9bcaa..8deb17e 100644 --- a/src/main/java/fathertoast/specialmobs/common/entity/ai/goal/ChargeCreeperGoal.java +++ b/src/main/java/fathertoast/specialmobs/common/entity/ai/goal/ChargeCreeperGoal.java @@ -1,6 +1,8 @@ package fathertoast.specialmobs.common.entity.ai.goal; import fathertoast.specialmobs.common.entity.MobHelper; +import fathertoast.specialmobs.common.entity.ai.IAmmoUser; +import mcp.MethodsReturnNonnullByDefault; import net.minecraft.entity.MobEntity; import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.monster.CreeperEntity; @@ -9,11 +11,14 @@ import net.minecraft.util.SoundEvents; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; +import javax.annotation.ParametersAreNonnullByDefault; import java.util.EnumSet; import java.util.List; import java.util.function.BiPredicate; -public class ChargeCreeperGoal extends Goal { +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class ChargeCreeperGoal extends Goal { private final BiPredicate targetPredicate; @@ -21,7 +26,7 @@ public class ChargeCreeperGoal extends Goal { private final double movementSpeed; private final double targetRange; - /** The creeper to target for power-up injection **/ + /** The creeper to target for power-up injection */ private CreeperEntity creeper; private int pathUpdateCooldown; @@ -45,7 +50,7 @@ public class ChargeCreeperGoal extends Goal { /** @return Returns true if this AI can be activated. */ @Override public boolean canUse() { - if( madman.isPassenger() || !canUseWhileMounted && madman.isVehicle() ) return false; + if( !madman.hasAmmo() || madman.isPassenger() || !canUseWhileMounted && madman.isVehicle() ) return false; findCreeper(); if( creeper == null ) return false; @@ -95,9 +100,12 @@ public class ChargeCreeperGoal extends Goal { madman.getLookControl().setLookAt( creeper, 30.0F, 30.0F ); if( distanceSq < 2.5 ) { - MobHelper.charge( creeper ); - madman.level.playSound( null, creeper.getX(), creeper.getY(), creeper.getZ(), - SoundEvents.BEE_STING, SoundCategory.HOSTILE, 0.9F, 1.0F ); + if( madman.hasAmmo() ) { + madman.consumeAmmo(); + MobHelper.charge( creeper ); + madman.level.playSound( null, creeper.getX(), creeper.getY(), creeper.getZ(), + SoundEvents.BEE_STING, SoundCategory.HOSTILE, 0.9F, 1.0F ); + } creeper = null; } diff --git a/src/main/java/fathertoast/specialmobs/common/entity/zombie/MadScientistZombieEntity.java b/src/main/java/fathertoast/specialmobs/common/entity/zombie/MadScientistZombieEntity.java index 3d8eaed..47518ee 100644 --- a/src/main/java/fathertoast/specialmobs/common/entity/zombie/MadScientistZombieEntity.java +++ b/src/main/java/fathertoast/specialmobs/common/entity/zombie/MadScientistZombieEntity.java @@ -3,18 +3,21 @@ package fathertoast.specialmobs.common.entity.zombie; import fathertoast.specialmobs.common.bestiary.BestiaryInfo; import fathertoast.specialmobs.common.bestiary.MobFamily; import fathertoast.specialmobs.common.bestiary.SpecialMob; +import fathertoast.specialmobs.common.config.species.MadScientistZombieSpeciesConfig; +import fathertoast.specialmobs.common.config.species.SpeciesConfig; import fathertoast.specialmobs.common.core.register.SMItems; import fathertoast.specialmobs.common.entity.MobHelper; import fathertoast.specialmobs.common.entity.ai.AIHelper; +import fathertoast.specialmobs.common.entity.ai.IAmmoUser; import fathertoast.specialmobs.common.entity.ai.goal.ChargeCreeperGoal; 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.Attributes; import net.minecraft.entity.monster.CreeperEntity; import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Effects; import net.minecraft.world.DifficultyInstance; @@ -28,7 +31,7 @@ import java.util.function.BiPredicate; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @SpecialMob -public class MadScientistZombieEntity extends _SpecialZombieEntity { +public class MadScientistZombieEntity extends _SpecialZombieEntity implements IAmmoUser { //--------------- Static Special Mob Hooks ---------------- @@ -38,10 +41,19 @@ public class MadScientistZombieEntity extends _SpecialZombieEntity { @SpecialMob.BestiaryInfoSupplier public static void getBestiaryInfo( BestiaryInfo.Builder bestiaryInfo ) { bestiaryInfo.color( 0xDED4C6 ) - .uniqueTextureWithOverlay() + .uniqueTextureBaseOnly() .addExperience( 2 ).disableRangedAttack(); } + @SpecialMob.ConfigSupplier + public static SpeciesConfig createConfig( MobFamily.Species species ) { + return new MadScientistZombieSpeciesConfig( species, 0.0, 0.0, 1, 3 ); + } + + /** @return This entity's species config. */ + @Override + public MadScientistZombieSpeciesConfig getConfig() { return (MadScientistZombieSpeciesConfig) getSpecies().config; } + @SpecialMob.LanguageProvider public static String[] getTranslations( String langKey ) { return References.translations( langKey, "Mad Scientist Zombie", @@ -65,10 +77,16 @@ public class MadScientistZombieEntity extends _SpecialZombieEntity { //--------------- Variant-Specific Implementations ---------------- - private final BiPredicate CHARGE_CREEPER_TARGET = ( madman, creeper ) -> + private static final BiPredicate CHARGE_CREEPER_TARGET = ( madman, creeper ) -> creeper.isAlive() && !creeper.isPowered() && madman.getSensing().canSee( creeper ); - public MadScientistZombieEntity( EntityType entityType, World world ) { super( entityType, world ); } + /** The number of creepers this madman can charge. */ + private int chargeCount; + + public MadScientistZombieEntity( EntityType entityType, World world ) { + super( entityType, world ); + chargeCount = getConfig().MAD_SCIENTIST.chargeCount.next( random ); + } /** Override to change this entity's AI goals. */ @Override @@ -91,11 +109,44 @@ public class MadScientistZombieEntity extends _SpecialZombieEntity { /** Override to apply effects when this entity hits a target with a melee attack. */ @Override protected void onVariantAttack( Entity target ) { - if( target instanceof LivingEntity && random.nextFloat() < 0.3F ) { + if( target instanceof LivingEntity && hasAmmo() ) { final LivingEntity livingTarget = (LivingEntity) target; final int duration = MobHelper.getDebuffDuration( level.getDifficulty() ); - livingTarget.addEffect( new EffectInstance( Effects.POISON, duration, 1 ) ); + livingTarget.addEffect( new EffectInstance( Effects.POISON, duration ) ); } } + + /** Called each tick to update this entity's movement. */ + @Override + public void aiStep() { + super.aiStep(); + + // We can't do this when the last charge is used, since it would change the AI during the AI loop + if( chargeCount <= 0 && getItemBySlot( EquipmentSlotType.MAINHAND ).getItem() == SMItems.SYRINGE.get() ) { + broadcastBreakEvent( EquipmentSlotType.MAINHAND ); + setItemSlot( EquipmentSlotType.MAINHAND, ItemStack.EMPTY ); + } + } + + /** @return True if this entity has ammo to use. */ + @Override + public boolean hasAmmo() { return chargeCount > 0; } + + /** Consumes ammo for a single use. */ + @Override + public void consumeAmmo() { chargeCount--; } + + /** Override to save data to this entity's NBT data. */ + @Override + public void addVariantSaveData( CompoundNBT saveTag ) { + saveTag.putByte( References.TAG_AMMO, (byte) chargeCount ); + } + + /** Override to load data from this entity's NBT data. */ + @Override + public void readVariantSaveData( CompoundNBT saveTag ) { + if( saveTag.contains( References.TAG_AMMO, References.NBT_TYPE_NUMERICAL ) ) + chargeCount = saveTag.getByte( References.TAG_AMMO ); + } } \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/common/util/References.java b/src/main/java/fathertoast/specialmobs/common/util/References.java index da8e10d..b079563 100644 --- a/src/main/java/fathertoast/specialmobs/common/util/References.java +++ b/src/main/java/fathertoast/specialmobs/common/util/References.java @@ -26,7 +26,7 @@ public final class References { public static final String TEXTURE_EYES_SUFFIX = "_eyes"; public static final String TEXTURE_OVERLAY_SUFFIX = "_overlay"; public static final String TEXTURE_SHOOTING_SUFFIX = "_shooting"; - public static final String TEXTURE_SHOOTING_EYES_SUFFIX = "_shooting_eyes"; + //public static final String TEXTURE_SHOOTING_EYES_SUFFIX = "_shooting_eyes"; //--------------- BIT FLAGS ---------------- @@ -113,7 +113,7 @@ public final class References { // Misc. public static final String TAG_FUSE_TIME = "FuseTime"; // Blackberry Slime, Volatile Magma Cube - public static final String TAG_AMMO = "Ammo"; // Web (Cave) Spider + public static final String TAG_AMMO = "Ammo"; // Web (Cave) Spider, Mad Scientist Zombie public static final String TAG_IS_FAKE = "IsFake"; // Mirage Enderman public static final String TAG_EXPLOSION_POWER = "ExplosionPower"; // Hellfire Blaze