Skip to content

Commit

Permalink
New hirschgeist sounds, redesign flame AoE attack to be projectile, b…
Browse files Browse the repository at this point in the history
…uff the HG, general fight polish, fix AoE attack making HG wait 10s to attack
  • Loading branch information
itsmeow committed Apr 18, 2022
1 parent d0ddeab commit e17ac92
Show file tree
Hide file tree
Showing 18 changed files with 219 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.itsmeow.imdlib.client.IMDLibClient;
import dev.itsmeow.imdlib.client.render.BaseRenderer;
import dev.itsmeow.imdlib.client.render.RenderFactory;
import dev.itsmeow.whisperwoods.WhisperwoodsMod;
import dev.itsmeow.whisperwoods.client.particle.FlameParticle;
Expand All @@ -16,20 +17,27 @@
import dev.itsmeow.whisperwoods.client.renderer.tile.RenderTileGhostLight;
import dev.itsmeow.whisperwoods.client.renderer.tile.RenderTileHandOfFate;
import dev.itsmeow.whisperwoods.entity.EntityHidebehind;
import dev.itsmeow.whisperwoods.entity.EntityWisp;
import dev.itsmeow.whisperwoods.entity.EntityZotzpyre;
import dev.itsmeow.whisperwoods.entity.projectile.EntityHirschgeistFireball;
import dev.itsmeow.whisperwoods.init.*;
import dev.itsmeow.whisperwoods.particle.WispParticleData;
import me.shedaniel.architectury.registry.BlockEntityRenderers;
import me.shedaniel.architectury.registry.RenderTypes;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Pose;
import org.apache.logging.log4j.LogManager;

Expand Down Expand Up @@ -77,6 +85,33 @@ public void render(PoseStack matrixStackIn, MultiBufferSource bufferIn, int pack
}
}));

RenderFactory.addRender(ModEntities.PROJECTILE_HIRSCHGEIST_FIREBALL.get(), t -> new EntityRenderer<EntityHirschgeistFireball>(t) {

@Override
public void render(EntityHirschgeistFireball entity, float f, float g, PoseStack poseStack, MultiBufferSource multiBufferSource, int i) {
if(!Minecraft.getInstance().isPaused()) {
if(System.nanoTime() - entity.lastSpawn >= 10_000_000L) {
entity.lastSpawn = System.nanoTime();
// spawn bottom particles
for(int j = 0; j < 5; j++) {
double xO = (entity.getRandom().nextFloat() * 2F - 1F);
double yO = (entity.getRandom().nextFloat() * 2F - 1F);
double zO = (entity.getRandom().nextFloat() * 2F - 1F);
entity.level.addParticle(ModParticles.SOUL_FLAME.get(),
entity.getX() + xO,
entity.getY() + yO,
entity.getZ() + zO, 0, 0.005F, 0);
}
}
}
}

@Override
public ResourceLocation getTextureLocation(EntityHirschgeistFireball entity) {
return null;
}
});

BlockEntityRenderers.registerRenderer(ModBlockEntities.GHOST_LIGHT.get(), RenderTileGhostLight::new);
BlockEntityRenderers.registerRenderer(ModBlockEntities.HG_SKULL.get(), RenderHGSkull::new);
BlockEntityRenderers.registerRenderer(ModBlockEntities.HAND_OF_FATE.get(), RenderTileHandOfFate::new);
Expand All @@ -89,6 +124,7 @@ public void render(PoseStack matrixStackIn, MultiBufferSource bufferIn, int pack
public static void registerParticles(BiConsumer<ParticleType<?>, Function<SpriteSet, ParticleProvider<?>>> register) {
register.accept(ModParticles.WISP.get(), WispParticle.WispFactory::new);
register.accept(ModParticles.FLAME.get(), FlameParticle.FlameFactory::new);
register.accept(ModParticles.SOUL_FLAME.get(), FlameParticle.FlameFactory::new);
}

public static class RenderTypeAddition extends RenderType {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package dev.itsmeow.whisperwoods.entity;

import dev.itsmeow.imdlib.entity.EntityTypeContainer;
import dev.itsmeow.whisperwoods.entity.projectile.EntityHirschgeistFireball;
import dev.itsmeow.whisperwoods.init.ModEntities;
import dev.itsmeow.whisperwoods.init.ModParticles;
import dev.itsmeow.whisperwoods.init.ModSounds;
import dev.itsmeow.whisperwoods.util.IOverrideCollisions;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
Expand All @@ -19,12 +22,12 @@
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.world.BossEvent;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
Expand Down Expand Up @@ -59,6 +62,7 @@ public class EntityHirschgeist extends Monster implements Enemy, IOverrideCollis
public EntityHirschgeist(EntityType<? extends EntityHirschgeist> entityType, Level worldIn) {
super(entityType, worldIn);
this.xpReward = 150;
this.maxUpStep = 1.5F;
}

@Override
Expand Down Expand Up @@ -161,6 +165,10 @@ public boolean doHurtTarget(Entity entityIn) {
if (entityIn instanceof LivingEntity) {
((LivingEntity) entityIn).knockback(2F, this.getX() - entityIn.getX(), this.getZ() - entityIn.getZ());
entityIn.setSecondsOnFire(2 + this.getRandom().nextInt(2));
if(level instanceof ServerLevel) {
ServerLevel serverLevel = (ServerLevel) level;
serverLevel.sendParticles(ParticleTypes.SOUL_FIRE_FLAME, this.position().x() + ((entityIn.position().x() - this.position().x()) / 2D), this.position().y() + ((entityIn.position().y() - this.position().y()) / 2D), this.position().z() + ((entityIn.position().z() - this.position().z()) / 2D), 500, Math.abs((entityIn.position().x() - this.position().x()) / 25D), 0, Math.abs((entityIn.position().z() - this.position().z()) / 25D), 0.1D);
}
}
return true;
}
Expand Down Expand Up @@ -214,10 +222,14 @@ public boolean isInvulnerableTo(DamageSource source) {

@Override
public boolean hurt(DamageSource source, float amount) {
if (this.isDaytime() && !this.level.isClientSide && !source.isCreativePlayer()) {
if (source.getEntity() instanceof Player) {
if(!this.level.isClientSide && source.getEntity() instanceof Player && !source.isCreativePlayer()) {
if (this.isDaytime()) {
Player player = (Player) source.getEntity();
player.sendMessage(new TranslatableComponent("entity.whisperwoods.hirschgeist.message.invulnerable"), Util.NIL_UUID);
return false;
} else if (this.getRandom().nextInt(4) == 0) {
this.level.playSound(null, source.getEntity(), SoundEvents.BUCKET_FILL_LAVA, SoundSource.MASTER, 1F, 2F);
return false;
}
}
return super.hurt(source, amount);
Expand All @@ -230,12 +242,17 @@ public void setTarget(LivingEntity entityIn) {

@Override
protected SoundEvent getAmbientSound() {
return this.getRandom().nextBoolean() ? SoundEvents.SKELETON_HORSE_AMBIENT : SoundEvents.RAVAGER_ROAR;
return ModSounds.HIRSCHGEIST_AMBIENT.get();
}

@Override
protected float getVoicePitch() {
return 0.3F; // Lower pitch of skeleton horse sound
protected SoundEvent getHurtSound(DamageSource damageSource) {
return ModSounds.HIRSCHGEIST_HURT.get();
}

@Override
protected SoundEvent getDeathSound() {
return ModSounds.HIRSCHGEIST_DEATH.get();
}

@Override
Expand Down Expand Up @@ -277,71 +294,36 @@ public EntityHirschgeist getImplementation() {
}

public static class FlameAttackGoal extends Goal {
private int flameTicks;
private final EntityHirschgeist attacker;
private final Level world;

public FlameAttackGoal(EntityHirschgeist creature) {
this.attacker = creature;
this.world = creature.level;
this.setFlags(EnumSet.of(Goal.Flag.LOOK));
}

@Override
public boolean canUse() {
return this.attacker.getTarget() != null && !this.attacker.isDaytime() && this.attacker.getTarget().isAlive();
return this.attacker.getTarget() != null && this.attacker.getRandom().nextInt(500) == 0;
}

@Override
public boolean canContinueToUse() {
return this.flameTicks <= 200 && this.attacker.getTarget() != null;
}

@Override
public void tick() {
++this.flameTicks;
LivingEntity target = this.attacker.getTarget();
if (this.flameTicks == 10 && target != null && target.distanceToSqr(this.attacker) <= 100) {
AreaEffectCloud areaEffectCloud = new AreaEffectCloud(target.level, target.getX(), target.getY(), target.getZ());
areaEffectCloud.setOwner(this.attacker);
areaEffectCloud.setRadius(3.0F);
areaEffectCloud.setDuration(2000);
areaEffectCloud.setParticle(ParticleTypes.SOUL_FIRE_FLAME);
areaEffectCloud.addEffect(new MobEffectInstance(MobEffects.HARM));
this.attacker.level.addFreshEntity(areaEffectCloud);
}

if (this.world.isClientSide) {
this.doClientRenderEffects();
}
}

public void doClientRenderEffects() {
if (this.flameTicks % 2 == 0 && this.flameTicks < 10 && this.attacker.getTarget() != null) {
LivingEntity target = this.attacker.getTarget();
Vec3 vec3d = this.attacker.getViewVector(1.0F).normalize();
vec3d.yRot(-((float) Math.PI / 4F));
double d0 = target.getX();
double d1 = target.getY();
double d2 = target.getZ();

for (int i = 0; i < 8; ++i) {
double d3 = d0 + this.attacker.getRandom().nextGaussian() / 2.0D;
double d4 = d1 + this.attacker.getRandom().nextGaussian() / 2.0D;
double d5 = d2 + this.attacker.getRandom().nextGaussian() / 2.0D;

for (int j = 0; j < 6; ++j) {
this.attacker.level.addParticle(ParticleTypes.FLAME, d3, d4, d5, -vec3d.x * 0.07999999821186066D * j, -vec3d.y * 0.6000000238418579D, -vec3d.z * 0.07999999821186066D * j);
}

vec3d.yRot(0.19634955F);
}
}
return false;
}

@Override
public void start() {
this.flameTicks = 0;
this.attacker.lookAt(this.attacker.getTarget(), 20, 20);
LivingEntity target = this.attacker.getTarget();
double d0 = target.getX() - this.attacker.getX();
double d1 = target.getY() - this.attacker.getEyeY() - 0.1D;
double d2 = target.getZ() - this.attacker.getZ();
double d3 = Mth.sqrt(d0 * d0 + d2 * d2);
EntityHirschgeistFireball ball = new EntityHirschgeistFireball(ModEntities.PROJECTILE_HIRSCHGEIST_FIREBALL.get(), this.attacker.level, this.attacker);
ball.setPos(target.getX(), target.getEyeY() - 0.1D, target.getZ());
ball.shoot(d0, d1 + d3 * 0.2D, d2, 0.5F, 2);
this.attacker.level.playSound(null, this.attacker, SoundEvents.EVOKER_CAST_SPELL, SoundSource.HOSTILE, 1F, 1F);
this.attacker.level.addFreshEntity(ball);
}

}
Expand All @@ -361,6 +343,7 @@ public boolean canUse() {
@Override
public void start() {
if(parent.level instanceof ServerLevel) {
this.parent.level.playSound(null, this.parent, SoundEvents.EVOKER_CAST_SPELL, SoundSource.HOSTILE, 1F, 1F);
for(int i = 0; i < 3; i++) {
EntityWisp wisp = ModEntities.WISP.getEntityType().create((ServerLevel) parent.level, null, null, null, parent.blockPosition().offset(parent.getRandom().nextInt(8) - 4 + 0.5D, parent.getRandom().nextInt(4) + 1 + 0.5D, parent.getRandom().nextInt(8) - 4 + 0.5D), MobSpawnType.REINFORCEMENT, false, false);
wisp.setHirschgeistSummon(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dev.itsmeow.whisperwoods.entity.projectile;

import dev.itsmeow.whisperwoods.init.ModParticles;
import me.shedaniel.architectury.networking.NetworkManager;
import net.minecraft.network.protocol.Packet;
import net.minecraft.util.Mth;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.ThrowableProjectile;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;

import java.util.Random;

public class EntityHirschgeistFireball extends ThrowableProjectile {

public LivingEntity thrower;
public long lastSpawn;
private Random random = new Random();

public EntityHirschgeistFireball(EntityType<? extends EntityHirschgeistFireball> entityType, Level worldIn) {
super(entityType, worldIn);
}

public EntityHirschgeistFireball(EntityType<? extends EntityHirschgeistFireball> entityType, Level worldIn, LivingEntity throwerIn) {
super(entityType, worldIn);
this.thrower = throwerIn;
}

public Random getRandom() {
return random;
}

public void shoot(double d, double e, double f, float g, float h) {
Vec3 vec3 = (new Vec3(d, e, f)).normalize().add(this.random.nextGaussian() * 0.0075D * (double)h, this.random.nextGaussian() * 0.0075D * (double)h, this.random.nextGaussian() * 0.0075D * (double)h).scale(g);
this.setDeltaMovement(vec3);
}

@Override
protected void onHit(HitResult result) {
if (!this.level.isClientSide) {
AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level, this.getX(), this.getY(), this.getZ());
areaEffectCloud.setOwner(this.thrower);
areaEffectCloud.setRadius(3.0F);
areaEffectCloud.setDuration(2000);
areaEffectCloud.setParticle(ModParticles.SOUL_FLAME.get());
areaEffectCloud.addEffect(new MobEffectInstance(MobEffects.HARM));
this.level.addFreshEntity(areaEffectCloud);
this.level.broadcastEntityEvent(this, (byte) 3);
this.remove();
}
}

@Override
public Packet<?> getAddEntityPacket() {
return NetworkManager.createAddEntityPacket(this);
}

@Override
protected void defineSynchedData() {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
import dev.itsmeow.whisperwoods.WhisperwoodsMod;
import dev.itsmeow.whisperwoods.entity.*;
import dev.itsmeow.whisperwoods.entity.EntityHidebehind.HidebehindVariant;
import dev.itsmeow.whisperwoods.entity.projectile.EntityHirschgeistFireball;
import me.shedaniel.architectury.registry.RegistrySupplier;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.Items;
import net.minecraft.world.phys.AABB;
import org.w3c.dom.Attr;

import java.util.LinkedHashMap;

Expand Down Expand Up @@ -70,8 +77,10 @@ public class ModEntities {

public static final EntityTypeContainer<EntityHirschgeist> HIRSCHGEIST = H.add(EntityHirschgeist.class, EntityHirschgeist::new, "hirschgeist", () -> Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 150.0D)
.add(Attributes.FOLLOW_RANGE, 50.0D)
.add(Attributes.MOVEMENT_SPEED, 0.65D)
.add(Attributes.FOLLOW_RANGE, 100.0D)
.add(Attributes.MOVEMENT_SPEED, 0.5D)
.add(Attributes.ARMOR, 10D)
.add(Attributes.ARMOR_TOUGHNESS, 5D)
.add(Attributes.ATTACK_DAMAGE)
.add(Attributes.ATTACK_DAMAGE, 6.0D), b -> b
.spawn(MobCategory.CREATURE, 2, 1, 1)
Expand All @@ -98,7 +107,13 @@ public static LinkedHashMap<String, EntityTypeContainer<? extends Mob>> getEntit
return H.ENTITIES;
}

public static final RegistrySupplier<EntityType<EntityHirschgeistFireball>> PROJECTILE_HIRSCHGEIST_FIREBALL = projectile(EntityHirschgeistFireball::new, "hirschgeist_fireball", 0.8F, 0.8F);

public static void init() {
H.init();
}

private static <T extends Projectile> RegistrySupplier<EntityType<T>> projectile(EntityType.EntityFactory<T> factory, String name, float width, float height) {
return IMDLib.getRegistry(Registry.ENTITY_TYPE_REGISTRY).registerSupplied(new ResourceLocation(WhisperwoodsMod.MODID, name), () -> H.createEntityType(factory, name, MobCategory.MISC, 64, 1, true, width, height));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@ public Codec<WispParticleData> codec() {
return WispParticleData.CODEC;
}
});
public static final RegistrySupplier<ParticleType<SimpleParticleType>> FLAME = r("flame", () -> new SimpleParticleType(false));
public static final RegistrySupplier<SimpleParticleType> FLAME = rSimple("flame", false);
public static final RegistrySupplier<SimpleParticleType> SOUL_FLAME = rSimple("soul_flame", false);

private static <T extends ParticleOptions> RegistrySupplier<ParticleType<T>> r(String name, Supplier<ParticleType<T>> b) {
return PARTICLES.register(name, b);
}

private static RegistrySupplier<SimpleParticleType> rSimple(String name, boolean override) {
return PARTICLES.register(name, () -> new SimpleParticleType(override));
}

public static void init() {
PARTICLES.register();
}
Expand Down
Loading

0 comments on commit e17ac92

Please sign in to comment.