diff --git a/src/main/java/io/redspace/ironsspellbooks/api/registry/SpellRegistry.java b/src/main/java/io/redspace/ironsspellbooks/api/registry/SpellRegistry.java index 5c329ceaa..aab0d7eeb 100644 --- a/src/main/java/io/redspace/ironsspellbooks/api/registry/SpellRegistry.java +++ b/src/main/java/io/redspace/ironsspellbooks/api/registry/SpellRegistry.java @@ -165,6 +165,7 @@ public static void onConfigReload() { public static final RegistryObject LIGHTNING_LANCE_SPELL = registerSpell(new LightningLanceSpell()); //public static final RegistryObject THUNDER_STEP_SPELL = registerSpell(new ThunderStepSpell()); public static final RegistryObject SHOCKWAVE_SPELL = registerSpell(new ShockwaveSpell()); + public static final RegistryObject THUNDERSTORM_SPELL = registerSpell(new ThunderstormSpell()); // NATURE public static final RegistryObject ACID_ORB_SPELL = registerSpell(new AcidOrbSpell()); diff --git a/src/main/java/io/redspace/ironsspellbooks/effect/ThunderstormEffect.java b/src/main/java/io/redspace/ironsspellbooks/effect/ThunderstormEffect.java new file mode 100644 index 000000000..3aac5319c --- /dev/null +++ b/src/main/java/io/redspace/ironsspellbooks/effect/ThunderstormEffect.java @@ -0,0 +1,63 @@ +package io.redspace.ironsspellbooks.effect; + +import io.redspace.ironsspellbooks.api.registry.SpellRegistry; +import io.redspace.ironsspellbooks.api.util.Utils; +import io.redspace.ironsspellbooks.capabilities.magic.MagicManager; +import io.redspace.ironsspellbooks.damage.DamageSources; +import io.redspace.ironsspellbooks.damage.ISpellDamageSource; +import io.redspace.ironsspellbooks.entity.spells.EchoingStrikeEntity; +import io.redspace.ironsspellbooks.entity.spells.LightningStrike; +import io.redspace.ironsspellbooks.registries.MobEffectRegistry; +import io.redspace.ironsspellbooks.util.ParticleHelper; +import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import javax.annotation.Nullable; + +@Mod.EventBusSubscriber +public class ThunderstormEffect extends MagicMobEffect { + public ThunderstormEffect(MobEffectCategory pCategory, int pColor) { + super(pCategory, pColor); + } + + @Override + public boolean isDurationEffectTick(int pDuration, int pAmplifier) { + return pDuration % 40 == 0; + } + + @Override + public void applyEffectTick(LivingEntity entity, int pAmplifier) { + var radiusSqr = 400; //20 + entity.level.getEntitiesOfClass(LivingEntity.class, entity.getBoundingBox().inflate(20, 12, 20), + livingEntity -> livingEntity != entity && + horizontalDistanceSqr(livingEntity, entity) < radiusSqr && + livingEntity.isPickable() && + !livingEntity.isSpectator() && + !DamageSources.isFriendlyFireBetween(livingEntity, entity) && + Utils.hasLineOfSight(entity.level, entity, livingEntity, false) + ) + .forEach(targetEntity -> { + LightningStrike lightningStrike = new LightningStrike(entity.level); + lightningStrike.setOwner(entity); + lightningStrike.setDamage(getDamageFromAmplifier(pAmplifier, entity)); + lightningStrike.setPos(targetEntity.position()); + entity.level.addFreshEntity(lightningStrike); + }); + } + + private float horizontalDistanceSqr(LivingEntity livingEntity, LivingEntity entity2) { + var dx = livingEntity.getX() - entity2.getX(); + var dz = livingEntity.getZ() - entity2.getZ(); + return (float) (dx * dx + dz * dz); + } + + public static float getDamageFromAmplifier(int effectAmplifier, @Nullable LivingEntity caster) { + var power = caster == null ? 1 : SpellRegistry.THUNDERSTORM_SPELL.get().getEntityPowerMultiplier(caster); + return (((effectAmplifier - 7) * power) + 7); + } +} diff --git a/src/main/java/io/redspace/ironsspellbooks/entity/spells/LightningStrike.java b/src/main/java/io/redspace/ironsspellbooks/entity/spells/LightningStrike.java index c6fa99feb..e72b602d5 100644 --- a/src/main/java/io/redspace/ironsspellbooks/entity/spells/LightningStrike.java +++ b/src/main/java/io/redspace/ironsspellbooks/entity/spells/LightningStrike.java @@ -1,10 +1,14 @@ package io.redspace.ironsspellbooks.entity.spells; import io.redspace.ironsspellbooks.api.registry.SchoolRegistry; +import io.redspace.ironsspellbooks.api.registry.SpellRegistry; +import io.redspace.ironsspellbooks.api.util.Utils; import io.redspace.ironsspellbooks.capabilities.magic.MagicManager; +import io.redspace.ironsspellbooks.damage.DamageSources; import io.redspace.ironsspellbooks.particle.ShockwaveParticleOptions; import io.redspace.ironsspellbooks.particle.SparkParticleOptions; import io.redspace.ironsspellbooks.particle.ZapParticleOption; +import io.redspace.ironsspellbooks.registries.EntityRegistry; import io.redspace.ironsspellbooks.registries.SoundRegistry; import io.redspace.ironsspellbooks.util.ParticleHelper; import net.minecraft.core.particles.ParticleOptions; @@ -12,29 +16,50 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import java.util.Optional; public class LightningStrike extends AoeEntity { public LightningStrike(EntityType pEntityType, Level pLevel) { super(pEntityType, pLevel); + setRadius(3); + setCircular(); + } + + public LightningStrike(Level level) { + this(EntityRegistry.LIGHTNING_STRIKE.get(), level); } static final int chargeTime = 20; + static final int vfxHeight = 15; @Override public void tick() { if (level.isClientSide) { return; } if (tickCount == 1) { + int total = 5; + int light = Utils.random.nextInt(total); + Vec3 location = this.position().add(0, vfxHeight, 0); + MagicManager.spawnParticles(level, ParticleHelper.FOG_THUNDER_LIGHT, location.x, location.y, location.z, light, 1, 1, 1, 1, true); + MagicManager.spawnParticles(level, ParticleHelper.FOG_THUNDER_DARK, location.x, location.y, location.z, total - light, 1, 1, 1, 1, true); MagicManager.spawnParticles(level, new ShockwaveParticleOptions(SchoolRegistry.LIGHTNING.get().getTargetingColor(), chargeTime * -1.5f * .05f, true), getX(), getY(), getZ(), 1, 0, 0, 0, 0, true); } if (tickCount == chargeTime) { checkHits(); - MagicManager.spawnParticles(level, ParticleHelper.ELECTRIC_SPARKS, getX(), getY(), getZ(), 25, .2f, .2f, .2f, .25, true); - MagicManager.spawnParticles(level, ParticleHelper.FIERY_SPARKS, getX(), getY(), getZ(), 5, .2f, .2f, .2f, .125, true); - MagicManager.spawnParticles(level, new ZapParticleOption(this.position().add(0, 20, 0)), getX(), getY(), getZ(), 1, 0, 0, 0, 0, true); - playSound(SoundRegistry.CHAIN_LIGHTNING_CHAIN.get(),2f,.5f+random.nextFloat()); + MagicManager.spawnParticles(level, ParticleHelper.ELECTRIC_SPARKS, getX(), getY(), getZ(), 25, .2f, .2f, .2f, .25, true); + MagicManager.spawnParticles(level, ParticleHelper.FIERY_SPARKS, getX(), getY(), getZ(), 5, .2f, .2f, .2f, .125, true); + Vec3 bottom = this.position(); + Vec3 top = bottom.add(0, vfxHeight, 0); + Vec3 middle = bottom.add(Utils.getRandomScaled(2), Utils.random.nextIntBetweenInclusive(3, vfxHeight - 3), Utils.getRandomScaled(2)); + MagicManager.spawnParticles(level, new ZapParticleOption(top), middle.x, middle.y, middle.z, 1, 0, 0, 0, 0, true); + MagicManager.spawnParticles(level, new ZapParticleOption(middle), getX(), getY(), getZ(), 1, 0, 0, 0, 0, true); + if (Utils.random.nextFloat() < .3f) { + Vec3 split = middle.add(Utils.getRandomScaled(2), -Math.abs(Utils.getRandomScaled(2)), Utils.getRandomScaled(2)); + MagicManager.spawnParticles(level, new ZapParticleOption(middle), split.x, split.y, split.z, 1, 0, 0, 0, 0, true); + } + playSound(SoundRegistry.SMALL_LIGHTNING_STRIKE.get(), 2f, .8f + random.nextFloat() * .5f); } if (this.tickCount > chargeTime) { discard(); @@ -43,7 +68,7 @@ public void tick() { @Override public void applyEffect(LivingEntity target) { - + DamageSources.applyDamage(target, getDamage(), SpellRegistry.THUNDERSTORM_SPELL.get().getDamageSource(this, getOwner())); } @Override diff --git a/src/main/java/io/redspace/ironsspellbooks/registries/EntityRegistry.java b/src/main/java/io/redspace/ironsspellbooks/registries/EntityRegistry.java index a446828a7..bd131a067 100644 --- a/src/main/java/io/redspace/ironsspellbooks/registries/EntityRegistry.java +++ b/src/main/java/io/redspace/ironsspellbooks/registries/EntityRegistry.java @@ -485,11 +485,12 @@ public static void register(IEventBus eventBus) { .clientTrackingRange(64) .build(new ResourceLocation(IronsSpellbooks.MODID, "stomp_aoe").toString())); -// public static final RegistryObject> LIGHTNING_STRIKE = -// ENTITIES.register("lightning_strike", () -> EntityType.Builder.of(LightningStrike::new, MobCategory.MISC) -// .sized(1f, 1f) -// .clientTrackingRange(64) -// .build(new ResourceLocation(IronsSpellbooks.MODID, "lightning_strike").toString())); + public static final RegistryObject> LIGHTNING_STRIKE = + ENTITIES.register("lightning_strike", () -> EntityType.Builder.of(LightningStrike::new, MobCategory.MISC) + .sized(1f, 1f) + .clientTrackingRange(64) + .build(new ResourceLocation(IronsSpellbooks.MODID, "lightning_strike").toString())); + public static final RegistryObject> APOTHECARIST = ENTITIES.register("apothecarist", () -> EntityType.Builder.of(ApothecaristEntity::new, MobCategory.MONSTER) .sized(.6f, 1.8f) diff --git a/src/main/java/io/redspace/ironsspellbooks/registries/MobEffectRegistry.java b/src/main/java/io/redspace/ironsspellbooks/registries/MobEffectRegistry.java index f71d8cc59..e6065e01f 100644 --- a/src/main/java/io/redspace/ironsspellbooks/registries/MobEffectRegistry.java +++ b/src/main/java/io/redspace/ironsspellbooks/registries/MobEffectRegistry.java @@ -52,5 +52,6 @@ public static void register(IEventBus eventBus) { public static final RegistryObject BURNING_DASH = MOB_EFFECT_DEFERRED_REGISTER.register("burning_dash", () -> new BurningDashEffect(MobEffectCategory.BENEFICIAL, 0xd0f9ff)); public static final RegistryObject GLUTTONY = MOB_EFFECT_DEFERRED_REGISTER.register("gluttony", () -> new GluttonyEffect(MobEffectCategory.BENEFICIAL, 0xd0f9ff)); public static final RegistryObject ECHOING_STRIKES = MOB_EFFECT_DEFERRED_REGISTER.register("echoing_strikes", () -> new EchoingStrikesEffect(MobEffectCategory.BENEFICIAL, 0x9f0be3)); + public static final RegistryObject THUNDERSTORM = MOB_EFFECT_DEFERRED_REGISTER.register("thunderstorm", () -> new ThunderstormEffect(MobEffectCategory.BENEFICIAL, 0x9f0be3)); //public static final RegistryObject ENCHANTED_WARD = MOB_EFFECT_DEFERRED_REGISTER.register("enchanted_ward", () -> new EnchantedWardEffect(MobEffectCategory.HARMFUL, 3311322)); } \ No newline at end of file diff --git a/src/main/java/io/redspace/ironsspellbooks/registries/SoundRegistry.java b/src/main/java/io/redspace/ironsspellbooks/registries/SoundRegistry.java index a36cb5609..5e47dd5c4 100644 --- a/src/main/java/io/redspace/ironsspellbooks/registries/SoundRegistry.java +++ b/src/main/java/io/redspace/ironsspellbooks/registries/SoundRegistry.java @@ -103,6 +103,8 @@ public static void register(IEventBus eventBus) { public static RegistryObject SCORCH_PREPARE = registerSoundEvent("spell.scorch.prepare"); public static RegistryObject FIERY_EXPLOSION = registerSoundEvent("entity.generic.fiery_explosion"); public static RegistryObject ECHOING_STRIKE = registerSoundEvent("entity.echoing_strike.echoing_strike"); + public static RegistryObject SMALL_LIGHTNING_STRIKE = registerSoundEvent("entity.lightning_strike.strike"); + public static RegistryObject THUNDERSTORM_PREPARE = registerSoundEvent("spell.thunderstorm.prepare"); public static RegistryObject DEAD_KING_SWING = registerSoundEvent("entity.dead_king.attack_swing"); public static RegistryObject DEAD_KING_SLAM = registerSoundEvent("entity.dead_king.attack_slam"); diff --git a/src/main/java/io/redspace/ironsspellbooks/setup/ClientSetup.java b/src/main/java/io/redspace/ironsspellbooks/setup/ClientSetup.java index 19adc0cb4..c7bd85db2 100644 --- a/src/main/java/io/redspace/ironsspellbooks/setup/ClientSetup.java +++ b/src/main/java/io/redspace/ironsspellbooks/setup/ClientSetup.java @@ -286,7 +286,7 @@ public static void rendererRegister(EntityRenderersEvent.RegisterRenderers event event.registerEntityRenderer(EntityRegistry.ARROW_VOLLEY_ENTITY.get(), NoopRenderer::new); event.registerEntityRenderer(EntityRegistry.STOMP_AOE.get(), NoopRenderer::new); event.registerEntityRenderer(EntityRegistry.ECHOING_STRIKE.get(), NoopRenderer::new); -// event.registerEntityRenderer(EntityRegistry.LIGHTNING_STRIKE.get(), NoopRenderer::new); + event.registerEntityRenderer(EntityRegistry.LIGHTNING_STRIKE.get(), NoopRenderer::new); event.registerBlockEntityRenderer(BlockRegistry.SCROLL_FORGE_TILE.get(), ScrollForgeRenderer::new); event.registerBlockEntityRenderer(BlockRegistry.PEDESTAL_TILE.get(), PedestalRenderer::new); diff --git a/src/main/java/io/redspace/ironsspellbooks/spells/lightning/ThunderstormSpell.java b/src/main/java/io/redspace/ironsspellbooks/spells/lightning/ThunderstormSpell.java new file mode 100644 index 000000000..ee650ffb0 --- /dev/null +++ b/src/main/java/io/redspace/ironsspellbooks/spells/lightning/ThunderstormSpell.java @@ -0,0 +1,99 @@ +package io.redspace.ironsspellbooks.spells.lightning; + +import com.mojang.math.Vector3f; +import io.redspace.ironsspellbooks.IronsSpellbooks; +import io.redspace.ironsspellbooks.api.config.DefaultConfig; +import io.redspace.ironsspellbooks.api.magic.MagicData; +import io.redspace.ironsspellbooks.api.registry.SchoolRegistry; +import io.redspace.ironsspellbooks.api.spells.*; +import io.redspace.ironsspellbooks.api.util.AnimationHolder; +import io.redspace.ironsspellbooks.api.util.CameraShakeData; +import io.redspace.ironsspellbooks.api.util.CameraShakeManager; +import io.redspace.ironsspellbooks.api.util.Utils; +import io.redspace.ironsspellbooks.capabilities.magic.MagicManager; +import io.redspace.ironsspellbooks.damage.DamageSources; +import io.redspace.ironsspellbooks.effect.ThunderstormEffect; +import io.redspace.ironsspellbooks.particle.BlastwaveParticleOptions; +import io.redspace.ironsspellbooks.particle.ZapParticleOption; +import io.redspace.ironsspellbooks.registries.MobEffectRegistry; +import io.redspace.ironsspellbooks.registries.SoundRegistry; +import io.redspace.ironsspellbooks.util.ParticleHelper; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LightningBolt; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.monster.Creeper; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import java.util.List; +import java.util.Optional; + +@AutoSpellConfig +public class ThunderstormSpell extends AbstractSpell { + private final ResourceLocation spellId = new ResourceLocation(IronsSpellbooks.MODID, "thunderstorm"); + + @Override + public List getUniqueInfo(int spellLevel, LivingEntity caster) { + return List.of( + Component.translatable("ui.irons_spellbooks.damage", Utils.stringTruncation(ThunderstormEffect.getDamageFromAmplifier(getAmplifierForLevel(spellLevel, caster), caster), 2)), + Component.translatable("ui.irons_spellbooks.radius", 20), + Component.translatable("ui.irons_spellbooks.effect_length", Utils.timeFromTicks(getDurationTicks(spellLevel, caster), 1)) + ); + } + + private final DefaultConfig defaultConfig = new DefaultConfig() + .setMinRarity(SpellRarity.RARE) + .setSchoolResource(SchoolRegistry.LIGHTNING_RESOURCE) + .setMaxLevel(8) + .setCooldownSeconds(120) + .build(); + + public ThunderstormSpell() { + this.manaCostPerLevel = 10; + this.baseSpellPower = 8; + this.spellPowerPerLevel = 1; + this.castTime = 40; + this.baseManaCost = 70; + } + + @Override + public CastType getCastType() { + return CastType.LONG; + } + + @Override + public DefaultConfig getDefaultConfig() { + return defaultConfig; + } + + @Override + public ResourceLocation getSpellResource() { + return spellId; + } + + @Override + public Optional getCastStartSound() { + return Optional.of(SoundRegistry.THUNDERSTORM_PREPARE.get()); + } + + @Override + public void onCast(Level level, int spellLevel, LivingEntity entity, CastSource castSource, MagicData playerMagicData) { + entity.addEffect(new MobEffectInstance(MobEffectRegistry.THUNDERSTORM.get(), getDurationTicks(spellLevel, entity), getAmplifierForLevel(spellLevel, entity), false, false, true)); + super.onCast(level, spellLevel, entity, castSource, playerMagicData); + } + + private int getAmplifierForLevel(int spellLevel, LivingEntity caster) { + return 8 + (int) ((spellLevel - 1) * getEntityPowerMultiplier(caster)); + } + + public int getDurationTicks(int spellLevel, LivingEntity caster) { + return (int) ((20 + (2 * (spellLevel - 1) * getEntityPowerMultiplier(caster))) * 20); + } +} diff --git a/src/main/java/io/redspace/ironsspellbooks/util/ParticleHelper.java b/src/main/java/io/redspace/ironsspellbooks/util/ParticleHelper.java index 1ae96e328..a37fc5ce5 100644 --- a/src/main/java/io/redspace/ironsspellbooks/util/ParticleHelper.java +++ b/src/main/java/io/redspace/ironsspellbooks/util/ParticleHelper.java @@ -24,6 +24,8 @@ public class ParticleHelper { public static final ParticleOptions VOID_TENTACLE_FOG = new FogParticleOptions(new Vector3f(0.0f, 0.075f, .13f), 2); public static final ParticleOptions ROOT_FOG = new FogParticleOptions(new Vector3f(61 / 255f, 40 / 255f, 18 / 255f), .4f); public static final ParticleOptions COMET_FOG = new FogParticleOptions(new Vector3f(.75f, .55f, 1f), 1.5f); + public static final ParticleOptions FOG_THUNDER_LIGHT = new FogParticleOptions(new Vector3f(.5f, .5f, .5f), 1.5f); + public static final ParticleOptions FOG_THUNDER_DARK = new FogParticleOptions(new Vector3f(.4f, .4f, .4f), 1.5f); public static final ParticleOptions POISON_CLOUD = new FogParticleOptions(new Vector3f(.08f, 0.64f, .16f), 1f); public static final ParticleOptions ICY_FOG = new FogParticleOptions(new Vector3f(208 / 255f, 249 / 255f, 255 / 255f), 0.6f); public static final ParticleOptions SUNBEAM = new FogParticleOptions(new Vector3f(0.95f, 0.97f, 0.36f), 1f); diff --git a/src/main/resources/assets/irons_spellbooks/lang/en_us.json b/src/main/resources/assets/irons_spellbooks/lang/en_us.json index a3e36be1c..0c01bd183 100644 --- a/src/main/resources/assets/irons_spellbooks/lang/en_us.json +++ b/src/main/resources/assets/irons_spellbooks/lang/en_us.json @@ -484,6 +484,7 @@ "spell.irons_spellbooks.echoing_strikes": "Echoing Strikes", "spell.irons_spellbooks.wololo": "Wololo", "spell.irons_spellbooks.scorch": "Scorch", + "spell.irons_spellbooks.thunderstorm": "Thunderstorm", "spell.irons_spellbooks.none.guide": "Nothing to see here!", "spell.irons_spellbooks.fireball.guide": "Manifest and throw a ball of fire, exploding and dealing massive damage on impact.", @@ -578,6 +579,7 @@ "spell.irons_spellbooks.echoing_strikes.guide": "While under the effects of the spell, non-magical attacks will leave an echo of ender energy behind, shortly thereafter exploding with an echo of the original attack's damage.", "spell.irons_spellbooks.wololo.guide": "Wololo!", "spell.irons_spellbooks.scorch.guide": "In a targeted area, erupt a scorch of fiery magic, damaging and inviting creatures in the zone.", + "spell.irons_spellbooks.thunderstorm.guide": "Cast to conjure a thunderstorm centered around yourself, which strikes nearby creatures with a small bolt of lightning every 2 seconds for the spell's duration.", "death.attack.blood_magic": "%1$s blood magic 1", "death.attack.blood_magic.item": "%1$s blood magic 2", diff --git a/src/main/resources/assets/irons_spellbooks/sounds.json b/src/main/resources/assets/irons_spellbooks/sounds.json index 4c163712e..70220f5f8 100644 --- a/src/main/resources/assets/irons_spellbooks/sounds.json +++ b/src/main/resources/assets/irons_spellbooks/sounds.json @@ -603,5 +603,15 @@ "sounds": [ "irons_spellbooks:echoing_strike" ] + }, + "entity.lightning_strike.strike": { + "sounds": [ + "irons_spellbooks:small_lightning" + ] + }, + "spell.thunderstorm.prepare": { + "sounds": [ + "irons_spellbooks:thunderstorm_prepare" + ] } } \ No newline at end of file diff --git a/src/main/resources/assets/irons_spellbooks/sounds/small_lightning.ogg b/src/main/resources/assets/irons_spellbooks/sounds/small_lightning.ogg new file mode 100644 index 000000000..0b611f540 Binary files /dev/null and b/src/main/resources/assets/irons_spellbooks/sounds/small_lightning.ogg differ diff --git a/src/main/resources/assets/irons_spellbooks/sounds/thunderstorm_prepare.ogg b/src/main/resources/assets/irons_spellbooks/sounds/thunderstorm_prepare.ogg new file mode 100644 index 000000000..77a86f909 Binary files /dev/null and b/src/main/resources/assets/irons_spellbooks/sounds/thunderstorm_prepare.ogg differ