From 6a2d9bb91f43f10108689342da3a0d472ca84aab Mon Sep 17 00:00:00 2001 From: Sarinsa Date: Mon, 4 Jul 2022 00:43:14 +0200 Subject: [PATCH] WIP Corporeal Shift Ghast --- .../specialmobs/client/ClientRegister.java | 22 ++- .../entity/CorporealShiftGhastModel.java | 55 ++++++ .../entity/CorporealShiftGhastRenderer.java | 53 ++++++ .../entity/layers/SpecialGhastEyesLayer.java | 42 +++++ .../renderer/entity/misc/SMRenderTypes.java | 24 +++ .../common/bestiary/MobFamily.java | 2 +- .../common/core/register/SMEntities.java | 6 + .../ghast/CorporealShiftGhastEntity.java | 170 ++++++++++++++++++ .../CorporealShiftFireballEntity.java | 147 +++++++++++++++ .../resources/META-INF/accesstransformer.cfg | 6 +- .../textures/entity/ghast/corporeal_shift.png | Bin 0 -> 3640 bytes .../entity/ghast/corporeal_shift_eyes.png | Bin 0 -> 164 bytes .../entity/ghast/corporeal_shift_shoot.png | Bin 0 -> 3660 bytes .../ghast/corporeal_shift_shoot_eyes.png | Bin 0 -> 195 bytes 14 files changed, 523 insertions(+), 4 deletions(-) create mode 100644 src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastModel.java create mode 100644 src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java create mode 100644 src/main/java/fathertoast/specialmobs/client/renderer/entity/layers/SpecialGhastEyesLayer.java create mode 100644 src/main/java/fathertoast/specialmobs/client/renderer/entity/misc/SMRenderTypes.java create mode 100644 src/main/java/fathertoast/specialmobs/common/entity/ghast/CorporealShiftGhastEntity.java create mode 100644 src/main/java/fathertoast/specialmobs/common/entity/projectile/CorporealShiftFireballEntity.java create mode 100644 src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift.png create mode 100644 src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_eyes.png create mode 100644 src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_shoot.png create mode 100644 src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_shoot_eyes.png diff --git a/src/main/java/fathertoast/specialmobs/client/ClientRegister.java b/src/main/java/fathertoast/specialmobs/client/ClientRegister.java index 4e3df63..ee13ce0 100644 --- a/src/main/java/fathertoast/specialmobs/client/ClientRegister.java +++ b/src/main/java/fathertoast/specialmobs/client/ClientRegister.java @@ -3,9 +3,17 @@ package fathertoast.specialmobs.client; import fathertoast.specialmobs.client.renderer.entity.*; import fathertoast.specialmobs.common.bestiary.MobFamily; import fathertoast.specialmobs.common.core.SpecialMobs; +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 mcp.MethodsReturnNonnullByDefault; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.entity.SpriteRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.IRendersAsItem; import net.minecraft.entity.LivingEntity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -15,6 +23,7 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.function.Supplier; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @@ -24,10 +33,10 @@ public class ClientRegister { @SubscribeEvent public static void onClientSetup( FMLClientSetupEvent event ) { ClientEventHandler.registerConfigGUIFactory(); - registerEntityRenderers(); + registerEntityRenderers( event.getMinecraftSupplier() ); } - private static void registerEntityRenderers() { + private static void registerEntityRenderers( Supplier game ) { // Family-based renderers registerFamilyRenderers( MobFamily.CREEPER, SpecialCreeperRenderer::new ); registerFamilyRenderers( MobFamily.ZOMBIE, SpecialZombieRenderer::new ); @@ -47,6 +56,10 @@ public class ClientRegister { // Species overrides 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 void registerFamilyRenderers( MobFamily family, IRenderFactory renderFactory ) { @@ -58,4 +71,9 @@ public class ClientRegister { private static void registerSpeciesRenderer( MobFamily.Species species, IRenderFactory renderFactory ) { RenderingRegistry.registerEntityRenderingHandler( species.entityType.get(), renderFactory ); } + + private static void registerSpriteRenderer(EntityType entityType, Supplier minecraftSupplier, float scale, boolean fullBright) { + ItemRenderer itemRenderer = minecraftSupplier.get().getItemRenderer(); + RenderingRegistry.registerEntityRenderingHandler(entityType, (renderManager) -> new SpriteRenderer<>(renderManager, itemRenderer, scale, fullBright)); + } } \ No newline at end of file diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastModel.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastModel.java new file mode 100644 index 0000000..c6be818 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastModel.java @@ -0,0 +1,55 @@ +package fathertoast.specialmobs.client.renderer.entity; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.model.SegmentedModel; +import net.minecraft.client.renderer.model.ModelRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; + +import java.util.Random; +import java.util.function.Function; + +/** Copy of {@link net.minecraft.client.renderer.entity.model.GhastModel} */ +public class CorporealShiftGhastModel extends SegmentedModel { + private final ModelRenderer[] tentacles = new ModelRenderer[9]; + private final ImmutableList parts; + + public CorporealShiftGhastModel() { + ImmutableList.Builder builder = ImmutableList.builder(); + ModelRenderer modelrenderer = new ModelRenderer(this, 0, 0); + modelrenderer.addBox(-8.0F, -8.0F, -8.0F, 16.0F, 16.0F, 16.0F); + modelrenderer.y = 17.6F; + builder.add(modelrenderer); + Random random = new Random(1660L); + + for (int i = 0; i < this.tentacles.length; ++i) { + this.tentacles[i] = new ModelRenderer(this, 0, 0); + float f = (((float) (i % 3) - (float) (i / 3 % 2) * 0.5F + 0.25F) / 2.0F * 2.0F - 1.0F) * 5.0F; + float f1 = ((float) (i / 3) / 2.0F * 2.0F - 1.0F) * 5.0F; + int j = random.nextInt(7) + 8; + this.tentacles[i].addBox(-1.0F, 0.0F, -1.0F, 2.0F, (float) j, 2.0F); + this.tentacles[i].x = f; + this.tentacles[i].z = f1; + this.tentacles[i].y = 24.6F; + builder.add(this.tentacles[i]); + } + + this.parts = builder.build(); + } + + public void setRenderType(Function renderTypeFunc) { + this.renderType = renderTypeFunc; + } + + public void setupAnim(T ghast, float p_225597_2_, float p_225597_3_, float p_225597_4_, float p_225597_5_, float p_225597_6_) { + for (int i = 0; i < this.tentacles.length; ++i) { + this.tentacles[i].xRot = 0.2F * MathHelper.sin(p_225597_4_ * 0.3F + (float) i) + 0.4F; + } + } + + public Iterable parts() { + return this.parts; + } +} diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java new file mode 100644 index 0000000..e29d24c --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/CorporealShiftGhastRenderer.java @@ -0,0 +1,53 @@ +package fathertoast.specialmobs.client.renderer.entity; + +import com.mojang.blaze3d.matrix.MatrixStack; +import fathertoast.specialmobs.client.renderer.entity.layers.SpecialGhastEyesLayer; +import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer; +import fathertoast.specialmobs.client.renderer.entity.misc.SMRenderTypes; +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 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 java.util.function.Function; + +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 final float baseShadowRadius; + + 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) { + model.renderType = ghast.isCorporeal() ? RenderType::entityCutoutNoCull : INCORPOREAL; + 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(); + shadowRadius = baseShadowRadius * scale; + matrixStack.scale( scale, scale, scale ); + } +} diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/layers/SpecialGhastEyesLayer.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/layers/SpecialGhastEyesLayer.java new file mode 100644 index 0000000..eea53c5 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/layers/SpecialGhastEyesLayer.java @@ -0,0 +1,42 @@ +package fathertoast.specialmobs.client.renderer.entity.layers; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import fathertoast.specialmobs.common.core.SpecialMobs; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.IEntityRenderer; +import net.minecraft.client.renderer.entity.layers.AbstractEyesLayer; +import net.minecraft.client.renderer.entity.model.EntityModel; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.entity.monster.GhastEntity; +import net.minecraft.util.ResourceLocation; + +public class SpecialGhastEyesLayer> extends AbstractEyesLayer { + private final RenderType FALLBACK = RenderType.eyes( new ResourceLocation( "textures/entity/spider_eyes.png" ) ); + private final ResourceLocation eyes; + private final ResourceLocation shootEyes; + + + public SpecialGhastEyesLayer( IEntityRenderer renderer, ResourceLocation eyes, ResourceLocation shootEyes ) { + super( renderer ); + this.eyes = eyes; + this.shootEyes = shootEyes; + } + + @Override + public void render(MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T ghast, float limbSwing, + float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch ) { + + IVertexBuilder vertexBuilder = buffer.getBuffer( RenderType.entityCutout(ghast.isCharging() ? shootEyes : eyes) ); + this.getParentModel().renderToBuffer( matrixStack, vertexBuilder, LightTexture.pack(15, 15), OverlayTexture.NO_OVERLAY, + 1.0F, 1.0F, 1.0F, 1.0F ); + } + + @Override + public RenderType renderType() { + SpecialMobs.LOG.warn( "Something is attempting to get eye layer 'render type' for some reason! :(" ); + return FALLBACK; + } +} diff --git a/src/main/java/fathertoast/specialmobs/client/renderer/entity/misc/SMRenderTypes.java b/src/main/java/fathertoast/specialmobs/client/renderer/entity/misc/SMRenderTypes.java new file mode 100644 index 0000000..8aee9ab --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/client/renderer/entity/misc/SMRenderTypes.java @@ -0,0 +1,24 @@ +package fathertoast.specialmobs.client.renderer.entity.misc; + +import net.minecraft.client.renderer.RenderState; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class SMRenderTypes { + + public static RenderState.AlphaState INCORPOREAL_ALPHA = new RenderState.AlphaState(0.05F); + + public static RenderType entityCutoutNoCullBlend(ResourceLocation resourceLocation, RenderState.AlphaState alphaState) { + RenderType.State state = RenderType.State.builder() + .setTextureState(new RenderState.TextureState(resourceLocation, false, false)) + .setTransparencyState(RenderState.ADDITIVE_TRANSPARENCY) + .setDiffuseLightingState(RenderState.DIFFUSE_LIGHTING) + .setAlphaState(alphaState) + .setLightmapState(RenderState.LIGHTMAP) + .setOverlayState(RenderState.OVERLAY) + .createCompositeState(true); + + return RenderType.create("specialmobs_entity_cutout_no_cull_blend", DefaultVertexFormats.NEW_ENTITY, 7, 256, true, false, state); + } +} diff --git a/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java b/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java index 97ff7c1..321c99a 100644 --- a/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java +++ b/src/main/java/fathertoast/specialmobs/common/bestiary/MobFamily.java @@ -97,7 +97,7 @@ public class MobFamily { public static final MobFamily GHAST = new MobFamily<>( "Ghast", "ghasts", 0xF9F9F9, new EntityType[] { EntityType.GHAST }, - "Baby", "Fighter", "King", "Queen", "Unholy" + "Baby", "Fighter", "King", "Queen", "Unholy", "CorporealShift" ); public static final MobFamily BLAZE = new MobFamily<>( diff --git a/src/main/java/fathertoast/specialmobs/common/core/register/SMEntities.java b/src/main/java/fathertoast/specialmobs/common/core/register/SMEntities.java index 4f34ea6..72ccb0a 100644 --- a/src/main/java/fathertoast/specialmobs/common/core/register/SMEntities.java +++ b/src/main/java/fathertoast/specialmobs/common/core/register/SMEntities.java @@ -2,8 +2,10 @@ package fathertoast.specialmobs.common.core.register; import fathertoast.specialmobs.common.bestiary.MobFamily; import fathertoast.specialmobs.common.core.SpecialMobs; +import fathertoast.specialmobs.common.entity.projectile.CorporealShiftFireballEntity; import fathertoast.specialmobs.common.util.AnnotationHelper; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityClassification; import net.minecraft.entity.EntityType; import net.minecraftforge.event.entity.EntityAttributeCreationEvent; import net.minecraftforge.fml.RegistryObject; @@ -13,6 +15,10 @@ import net.minecraftforge.registries.ForgeRegistries; public class SMEntities { public static final DeferredRegister> REGISTRY = DeferredRegister.create( ForgeRegistries.ENTITIES, SpecialMobs.MOD_ID ); + + /** Misc entities */ + public static final RegistryObject> CORPOREAL_FIREBALL = register("corporeal_fireball", + EntityType.Builder.of(CorporealShiftFireballEntity::new, EntityClassification.MISC).sized(1.0F, 1.0F).clientTrackingRange(4).updateInterval(10)); /** Registers an entity type to the deferred register. */ public static RegistryObject> register( String name, EntityType.Builder builder ) { diff --git a/src/main/java/fathertoast/specialmobs/common/entity/ghast/CorporealShiftGhastEntity.java b/src/main/java/fathertoast/specialmobs/common/entity/ghast/CorporealShiftGhastEntity.java new file mode 100644 index 0000000..56807f4 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/common/entity/ghast/CorporealShiftGhastEntity.java @@ -0,0 +1,170 @@ +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.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 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; + +@SpecialMob +public class CorporealShiftGhastEntity extends _SpecialGhastEntity { + + //--------------- Static Special Mob Hooks ---------------- + + @SpecialMob.SpeciesReference + public static MobFamily.Species SPECIES; + + @SpecialMob.BestiaryInfoSupplier + public static BestiaryInfo bestiaryInfo(EntityType.Builder entityType ) { + entityType.sized( 6.0F, 6.0F ); + return new BestiaryInfo( 0xA7FF9B, BestiaryInfo.BaseWeight.LOW ); + } + + @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", Items.POISONOUS_POTATO ); + } + + @SpecialMob.Factory + public static EntityType.IFactory getVariantFactory() { return CorporealShiftGhastEntity::new; } + + + //--------------- Variant-Specific Implementations ---------------- + + public static final DataParameter CORPOREAL = EntityDataManager.defineId(CorporealShiftGhastEntity.class, DataSerializers.BOOLEAN); + + private final int maxShiftTime = 600; + private int shiftTime = maxShiftTime; + + public CorporealShiftGhastEntity( EntityType entityType, World world ) { + super( entityType, world ); + getSpecialData().setRegenerationTime( 80 ); + getSpecialData().setBaseScale( 1.0F ); + xpReward += 2; + } + + @Override + protected void defineSynchedData() { + super.defineSynchedData(); + entityData.define(CORPOREAL, false); + } + + @Override + public void tick() { + super.tick(); + + if ( --shiftTime <= 0 ) { + if ( !level.isClientSide ) { + shiftTime = maxShiftTime; + entityData.set(CORPOREAL, !entityData.get(CORPOREAL)); + 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); + } + + public boolean isCorporeal() { + return entityData.get(CORPOREAL); + } + + /** 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 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( + getX() + lookVec.x, + getY( 0.5 ) + 0.5, + 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); + } + + /** Saves data to this entity's base NBT compound that is specific to its subclass. */ + @Override + public void addAdditionalSaveData( CompoundNBT tag ) { + super.addAdditionalSaveData( tag ); + tag.putInt("ShiftTime", shiftTime); + } + + /** Loads data from this entity's base NBT compound that is specific to its subclass. */ + @Override + public void readAdditionalSaveData( CompoundNBT tag ) { + super.readAdditionalSaveData( tag ); + + if (tag.contains("ShiftTime", Constants.NBT.TAG_ANY_NUMERIC)) { + shiftTime = tag.getInt("ShiftTime"); + } + } +} diff --git a/src/main/java/fathertoast/specialmobs/common/entity/projectile/CorporealShiftFireballEntity.java b/src/main/java/fathertoast/specialmobs/common/entity/projectile/CorporealShiftFireballEntity.java new file mode 100644 index 0000000..012e630 --- /dev/null +++ b/src/main/java/fathertoast/specialmobs/common/entity/projectile/CorporealShiftFireballEntity.java @@ -0,0 +1,147 @@ +package fathertoast.specialmobs.common.entity.projectile; + +import fathertoast.specialmobs.common.bestiary.SpecialMob; +import fathertoast.specialmobs.common.core.SpecialMobs; +import fathertoast.specialmobs.common.core.register.SMEntities; +import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity; +import fathertoast.specialmobs.common.util.References; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.projectile.AbstractFireballEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.IPacket; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.EntityRayTraceResult; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.Explosion; +import net.minecraft.world.World; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.fml.network.NetworkHooks; + +public class CorporealShiftFireballEntity extends AbstractFireballEntity { + + private static final DataParameter CORPOREAL = EntityDataManager.defineId(CorporealShiftFireballEntity.class, DataSerializers.BOOLEAN); + + public int explosionPower = 1; + private boolean shouldExplode = false; + + + public CorporealShiftFireballEntity(EntityType 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()); + } + + @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); + } + + public boolean isCorporeal() { + return entityData.get(CORPOREAL); + } + + public void setCorporeal(boolean corporeal) { + entityData.set(CORPOREAL, corporeal); + } + + @Override + public void tick() { + super.tick(); + + 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); + remove(); + } + + + @Override + protected void onHit(RayTraceResult traceResult) { + super.onHit(traceResult); + + if (!level.isClientSide && isCorporeal()) { + shouldExplode = true; + } + } + + @Override + protected void onHitEntity(EntityRayTraceResult traceResult) { + super.onHitEntity(traceResult); + + if (!this.level.isClientSide) { + Entity target = traceResult.getEntity(); + Entity owner = getOwner(); + + if (!isCorporeal()) { + // TODO - Figure out why this is cringe + 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 { + 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()) { + return false; + } + shouldExplode = true; + return true; + } + else { + return super.hurt(damageSource, damage); + } + } + + @Override + public void addAdditionalSaveData(CompoundNBT compoundNBT) { + super.addAdditionalSaveData(compoundNBT); + compoundNBT.putInt("ExplosionPower", explosionPower); + compoundNBT.putBoolean("Corporeal", isCorporeal()); + } + + @Override + public void readAdditionalSaveData(CompoundNBT compoundNBT) { + super.readAdditionalSaveData(compoundNBT); + if (compoundNBT.contains("ExplosionPower", 99)) { + explosionPower = compoundNBT.getInt("ExplosionPower"); + } + entityData.set(CORPOREAL, compoundNBT.getBoolean("Corporeal")); + } + + @Override + public IPacket getAddEntityPacket() { + return NetworkHooks.getEntitySpawningPacket(this); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 0120535..4c8a2c7 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -2,7 +2,11 @@ # anything inside a final class, and private and/or static fields & methods. # Render stuff -public net.minecraft.client.renderer.WorldRenderer field_228415_m_ # renderBuffers +public-f net.minecraft.client.renderer.model.Model field_228281_q_ # renderType +public net.minecraft.client.renderer.RenderState field_228511_c_ # ADDITIVE_TRANSPARENCY +public net.minecraft.client.renderer.RenderState field_228532_x_ # DIFFUSE_LIGHTING +public net.minecraft.client.renderer.RenderState field_228528_t_ # LIGHTMAP +public net.minecraft.client.renderer.RenderState field_228530_v_ # OVERLAY # LIGHTMAP # Entity registration public net.minecraft.entity.EntityType field_233593_bg_ # immuneTo diff --git a/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift.png b/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift.png new file mode 100644 index 0000000000000000000000000000000000000000..16f93e58b402f7fc25e441e31766066a196324ff GIT binary patch literal 3640 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 KMNUMnLSTa2iRFm^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_eyes.png b/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..86dfe3594d656b106a603323afd6612f6116ed38 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4uLSEsD@VqP|(uT#W5tq`R&!6ybKCF%m+67zfj}l&F<8( z``9$`0-yp0hCfSE@&b3S34ZCeu8d*F>l?B=?J68xnB%;8m@ONl4uX_;y85}Sb4q9e E0N>3n(f|Me literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_shoot.png b/src/main/resources/assets/specialmobs/textures/entity/ghast/corporeal_shift_shoot.png new file mode 100644 index 0000000000000000000000000000000000000000..97d298154cc52ee8b4eec84885e5805c7fde9f89 GIT binary patch literal 3660 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 l9rcefb}nnckyAB6Rt#02w4YBpuzM;