diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/compat/ArcanusConfig.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/compat/ArcanusConfig.java index edcd672..6322084 100644 --- a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/compat/ArcanusConfig.java +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/compat/ArcanusConfig.java @@ -72,6 +72,7 @@ public class ArcanusConfig extends MidnightConfig { @Entry public static SpellEffectProperties copperCurseEffectProperties = new SpellEffectProperties(true, Weight.NONE, 8, 0, 8) { @Entry public int baseEffectDuration = 24000; @Entry public int effectDurationModifier = 12000; + @Entry public double baseChanceToActivate = 0.0625; }; @Entry public static SpellEffectProperties discombobulateEffectProperties = new SpellEffectProperties(true, Weight.NONE, 6, 0, 5) { @Entry public int baseEffectDuration = 60; @@ -100,6 +101,10 @@ public class ArcanusConfig extends MidnightConfig { @Entry public int baseLifeSpan = 100; @Entry public int lifeSpanModifier = 40; }; + @Entry public static SpellEffectProperties dangerSenseEffectProperties = new SpellEffectProperties(true, Weight.NONE, 5, 0, 8) { + @Entry public int baseEffectDuration = 100; + @Entry public double baseChanceToActivate = 0.025; + }; // @Entry public static SpellEffectProperties temporalDilationEffectProperties = new SpellEffectProperties(true, Weight.NONE, 10, 0, 10) { // @Entry public int baseEffectDuration = 100; // @Entry public boolean affectsPlayers = true; diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusSpellComponents.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusSpellComponents.java index efda793..d4c17d8 100644 --- a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusSpellComponents.java +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusSpellComponents.java @@ -65,6 +65,7 @@ public void cast(@Nullable LivingEntity caster, Vec3d castFrom, @Nullable Entity public static final RegistrySupplier HASTE = SPELL_COMPONENTS.register("haste_effect", () -> new HasteSpellEffect(hasteEffectProperties.enabled, SpellType.SUPPORT, hasteEffectProperties.weight, hasteEffectProperties.manaCost, hasteEffectProperties.coolDown, hasteEffectProperties.minimumLevel)); public static final RegistrySupplier MANA_SHIELD = SPELL_COMPONENTS.register("mana_shield_effect", () -> new ManaShieldSpellEffect(manaShieldEffectProperties.enabled, SpellType.SUPPORT, manaShieldEffectProperties.weight, manaShieldEffectProperties.manaCost, manaShieldEffectProperties.coolDown, manaShieldEffectProperties.minimumLevel)); // public static final RegistrySupplier TEMPORAL_DILATION = SPELL_COMPONENTS.register("temporal_dilation_effect", () -> new TemporalDilationSpellEffect(temporalDilationEffectProperties.enabled, SpellType.SUPPORT, temporalDilationEffectProperties.weight, temporalDilationEffectProperties.manaCost, temporalDilationEffectProperties.coolDown, temporalDilationEffectProperties.minimumLevel)); + public static final RegistrySupplier DANGER_SENSE = SPELL_COMPONENTS.register("danger_sense_effect", () -> new DangerSenseSpellEffect(dangerSenseEffectProperties.enabled, SpellType.SUPPORT, dangerSenseEffectProperties.weight, dangerSenseEffectProperties.manaCost, dangerSenseEffectProperties.coolDown, dangerSenseEffectProperties.minimumLevel)); public static final RegistrySupplier PUSH = SPELL_COMPONENTS.register("push_effect", () -> new PushSpellEffect(pushEffectProperties.enabled, SpellType.UTILITY, pushEffectProperties.weight, pushEffectProperties.manaCost, pushEffectProperties.coolDown, pushEffectProperties.minimumLevel)); public static final RegistrySupplier PULL = SPELL_COMPONENTS.register("pull_effect", () -> new PullSpellEffect(pullEffectProperties.enabled, SpellType.UTILITY, pullEffectProperties.weight, pullEffectProperties.manaCost, pullEffectProperties.coolDown, pullEffectProperties.minimumLevel)); diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusStatusEffects.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusStatusEffects.java index ae3a4ed..c89329b 100644 --- a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusStatusEffects.java +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/registry/ArcanusStatusEffects.java @@ -24,4 +24,5 @@ public class ArcanusStatusEffects { public static final RegistrySupplier ANTI_GRAVITY = STATUS_EFFECTS.register("anti_gravity", () -> new ArcanusStatusEffect(StatusEffectType.NEUTRAL, 0xceffff)); public static final RegistrySupplier MANA_WINGS = STATUS_EFFECTS.register("mana_wings", () -> new ArcanusStatusEffect(StatusEffectType.BENEFICIAL, 0x716e8c)); public static final RegistrySupplier STOCKPILE = STATUS_EFFECTS.register("stockpile", () -> new ArcanusStatusEffect(StatusEffectType.BENEFICIAL, 0x550000)); + public static final RegistrySupplier DANGER_SENSE = STATUS_EFFECTS.register("danger_sense", () -> new ArcanusStatusEffect(StatusEffectType.BENEFICIAL, 0xaeeff2)); } diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/common/spell_components/effects/DangerSenseSpellEffect.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/spell_components/effects/DangerSenseSpellEffect.java new file mode 100644 index 0000000..9f73cc2 --- /dev/null +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/common/spell_components/effects/DangerSenseSpellEffect.java @@ -0,0 +1,35 @@ +package dev.cammiescorner.arcanuscontinuum.common.spell_components.effects; + +import dev.cammiescorner.arcanuscontinuum.api.spells.SpellEffect; +import dev.cammiescorner.arcanuscontinuum.api.spells.SpellType; +import dev.cammiescorner.arcanuscontinuum.api.spells.Weight; +import dev.cammiescorner.arcanuscontinuum.common.effects.ArcanusStatusEffect; +import dev.cammiescorner.arcanuscontinuum.common.registry.ArcanusSpellComponents; +import dev.cammiescorner.arcanuscontinuum.common.registry.ArcanusStatusEffects; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class DangerSenseSpellEffect extends SpellEffect { + public DangerSenseSpellEffect(boolean isEnabled, SpellType type, Weight weight, double manaCost, int coolDown, int minLevel) { + super(isEnabled, type, weight, manaCost, coolDown, minLevel); + } + + @Override + public void effect(@Nullable LivingEntity caster, @Nullable Entity sourceEntity, World world, HitResult target, List effects, ItemStack stack, double potency) { + if(target.getType() == HitResult.Type.ENTITY) { + EntityHitResult entityHit = (EntityHitResult) target; + + if(entityHit.getEntity() instanceof LivingEntity livingEntity) + livingEntity.addStatusEffect(new StatusEffectInstance(ArcanusStatusEffects.DANGER_SENSE.get(), 200, (int) ((effects.stream().filter(ArcanusSpellComponents.DANGER_SENSE::is).count() - 1) * potency), true, false)); + } + } +} diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/ExplosionMixin.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/ExplosionMixin.java new file mode 100644 index 0000000..feebc8c --- /dev/null +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/ExplosionMixin.java @@ -0,0 +1,30 @@ +package dev.cammiescorner.arcanuscontinuum.mixin.common; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.explosion.Explosion; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Slice; + +@Mixin(Explosion.class) +public class ExplosionMixin { + @ModifyExpressionValue(method = "collectBlocksAndDamageEntities", at = @At(value = "INVOKE", + target = "Lnet/minecraft/entity/Entity;damage(Lnet/minecraft/entity/damage/DamageSource;F)Z" + )) + private boolean arcanuscontinuum$captureDamageReturn(boolean original, @Share("tookDamage") LocalBooleanRef ref) { + ref.set(original); + return original; + } + + @ModifyExpressionValue(method = "collectBlocksAndDamageEntities", slice = @Slice(from = @At(value = "INVOKE", + target = "Lnet/minecraft/entity/Entity;damage(Lnet/minecraft/entity/damage/DamageSource;F)Z" + )), at = @At(value = "NEW", + target = "(DDD)Lnet/minecraft/util/math/Vec3d;" + )) + private Vec3d arcanuscontinuum$noKnockback(Vec3d original, @Share("tookDamage") LocalBooleanRef ref) { + return !ref.get() ? Vec3d.ZERO : original; + } +} diff --git a/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/LivingEntityMixin.java b/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/LivingEntityMixin.java index 2f8a02d..7f6cfb1 100644 --- a/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/LivingEntityMixin.java +++ b/src/main/java/dev/cammiescorner/arcanuscontinuum/mixin/common/LivingEntityMixin.java @@ -21,16 +21,21 @@ import net.minecraft.entity.damage.DamageTypes; import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.passive.FoxEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import net.minecraft.registry.tag.DamageTypeTags; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -63,11 +68,13 @@ public abstract class LivingEntityMixin extends Entity implements Targetable { @Shadow public abstract boolean addStatusEffect(StatusEffectInstance effect); @Shadow public abstract float getMovementSpeed(); + @Shadow public abstract boolean teleport(double x, double y, double z, boolean particleEffects); + public LivingEntityMixin(EntityType type, World world) { super(type, world); } - @Inject(method = "damage", at = @At("HEAD")) + @Inject(method = "damage", at = @At("HEAD"), cancellable = true) private void arcanuscontinuum$onDamage(DamageSource source, float amount, CallbackInfoReturnable info) { if(amount > 0 && !blockedByShield(source)) { if(hasStatusEffect(ArcanusStatusEffects.MANA_WINGS.get())) @@ -84,6 +91,44 @@ public LivingEntityMixin(EntityType type, World world) { addStatusEffect(new StatusEffectInstance(stockpile.getEffectType(), stockpile.getDuration(), stockpile.getAmplifier() + MathHelper.floor(Math.round(amount) / 10f))); } } + + if(hasStatusEffect(ArcanusStatusEffects.DANGER_SENSE.get()) && (source.isTypeIn(DamageTypeTags.IS_PROJECTILE) || source.isTypeIn(DamageTypeTags.IS_EXPLOSION))) { + StatusEffectInstance dangerSense = getStatusEffect(ArcanusStatusEffects.DANGER_SENSE.get()); + + if(random.nextFloat() < 0.025 * (dangerSense.getAmplifier() + 1)) { + if(getWorld() instanceof ServerWorld world) { + double d = getX(); + double e = getY(); + double f = getZ(); + + for(int i = 0; i < 16; ++i) { + double g = getX() + (random.nextDouble() - 0.5) * 16.0; + double h = MathHelper.clamp( + getY() + random.nextInt(16) - 8, + world.getBottomY(), + world.getBottomY() + world.getLogicalHeight() - 1 + ); + double j = getZ() + (random.nextDouble() - 0.5) * 16.0; + + if(hasVehicle()) + stopRiding(); + + Vec3d vec3d = getPos(); + + if(teleport(g, h, j, true)) { + world.emitGameEvent(GameEvent.TELEPORT, vec3d, GameEvent.Context.create(self)); + SoundEvent soundEvent = self instanceof FoxEntity ? SoundEvents.ENTITY_FOX_TELEPORT : SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT; + world.playSound(null, d, e, f, soundEvent, SoundCategory.PLAYERS, 1f, 1f); + playSound(soundEvent, 1f, 1f); + break; + } + } + } + + removeStatusEffect(ArcanusStatusEffects.DANGER_SENSE.get()); + info.setReturnValue(false); + } + } } } diff --git a/src/main/resources/arcanuscontinuum.mixins.json b/src/main/resources/arcanuscontinuum.mixins.json index 8879c23..4520891 100644 --- a/src/main/resources/arcanuscontinuum.mixins.json +++ b/src/main/resources/arcanuscontinuum.mixins.json @@ -8,6 +8,7 @@ "common.AbstractBlockStateMixin", "common.EntityPartMixin", "common.EntityViewMixin", + "common.ExplosionMixin", "common.FallingBlockMixin", "common.HungerManagerMixin", "common.ItemEntityMixin", diff --git a/src/main/resources/assets/arcanuscontinuum/lang/en_us.json b/src/main/resources/assets/arcanuscontinuum/lang/en_us.json index 4f5bd79..1e9a8ed 100644 --- a/src/main/resources/assets/arcanuscontinuum/lang/en_us.json +++ b/src/main/resources/assets/arcanuscontinuum/lang/en_us.json @@ -59,6 +59,7 @@ "effect.arcanuscontinuum.anti_gravity": "Anti-Gravity", "effect.arcanuscontinuum.mana_wings": "Mana Wings", "effect.arcanuscontinuum.stockpile": "Stockpile", + "effect.arcanuscontinuum.danger_sense": "Danger Sense", "advancements.arcanuscontinuum.root.title": "Arcanus: Continuum", "advancements.arcanuscontinuum.root.description": "[insert witty sales pitch for something you're already playing]", @@ -146,6 +147,7 @@ "spell_component.arcanuscontinuum.anti_gravity_effect": "Anti-Gravity Effect", "spell_component.arcanuscontinuum.mana_wings_effect": "Mana Wings Effect", "spell_component.arcanuscontinuum.stockpile_effect": "Stockpile Effect", + "spell_component.arcanuscontinuum.danger_sense_effect": "Danger Sense", "item.arcanuscontinuum.compendium_arcanus.landing_text": "Arcanus: Continuum introduces a new magic system to the world of Minecraft. Players can create their own custom spells to suit however they like to play the game!", @@ -426,6 +428,13 @@ "arcanuscontinuum.midnightconfig.manaShieldEffectProperties.coolDown": "Cool Down", "arcanuscontinuum.midnightconfig.manaShieldEffectProperties.minimumLevel": "Minimum Level", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties": "Danger Sense Effect Properties", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties.enabled": "Enabled", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties.weight": "Weight", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties.manaCost": "Mana Cost", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties.coolDown": "Cool Down", + "arcanuscontinuum.midnightconfig.dangerSenseEffectProperties.minimumLevel": "Minimum Level", + "arcanuscontinuum.midnightconfig.pushEffectProperties": "Push Effect Properties",