160 lines
8.0 KiB
Java
160 lines
8.0 KiB
Java
package net.fretux.ailments.event;
|
|
|
|
import net.fretux.ailments.AscendAilments;
|
|
import net.fretux.ailments.api.AilmentApi;
|
|
import net.fretux.ailments.config.AilmentsConfig;
|
|
import net.fretux.ailments.registry.ModEffects;
|
|
import net.fretux.ailments.util.ControlEffectHelper;
|
|
import net.fretux.ailments.util.EffectSourceUtil;
|
|
import net.fretux.ailments.util.MentalControlUtil;
|
|
import net.fretux.ailments.util.ModItemTags;
|
|
import net.fretux.ailments.util.HemorrhageTracker;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraftforge.event.entity.living.LivingAttackEvent;
|
|
import net.minecraftforge.event.entity.living.LivingChangeTargetEvent;
|
|
import net.minecraftforge.event.entity.living.LivingEvent;
|
|
import net.minecraftforge.event.entity.living.LivingDeathEvent;
|
|
import net.minecraftforge.event.entity.living.LivingHealEvent;
|
|
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
import net.minecraftforge.registries.ForgeRegistries;
|
|
|
|
import java.util.Locale;
|
|
|
|
/** One deterministic damage pipeline: Soul Rot, Charm, Taunt, then Overcharm. */
|
|
@Mod.EventBusSubscriber(modid = AscendAilments.MOD_ID)
|
|
public final class AilmentEvents {
|
|
@SubscribeEvent
|
|
public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
|
|
HemorrhageTracker.syncDisplay(event.getEntity());
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) {
|
|
HemorrhageTracker.hideDisplay(event.getEntity());
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onDeath(LivingDeathEvent event) {
|
|
HemorrhageTracker.clear(event.getEntity());
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onLivingTick(LivingEvent.LivingTickEvent event) {
|
|
ControlEffectHelper.handleLivingTick(event.getEntity());
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onHeal(LivingHealEvent event) {
|
|
if (!event.isCanceled() && event.getEntity().hasEffect(ModEffects.SOUL_ROT.get()))
|
|
event.setAmount((float) (event.getAmount() * AilmentsConfig.value(AilmentsConfig.SOUL_ROT_HEALING)));
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onAttack(LivingAttackEvent event) {
|
|
Entity attacker = event.getSource().getEntity();
|
|
if (attacker instanceof LivingEntity living && !(living instanceof Player)
|
|
&& living.hasEffect(ModEffects.CHARM.get())
|
|
&& ControlEffectHelper.isOwnCharmSource(living, event.getEntity())) event.setCanceled(true);
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onChangeTarget(LivingChangeTargetEvent event) {
|
|
if (!(event.getEntity() instanceof Mob mob)) return;
|
|
LivingEntity taunter = mob.hasEffect(ModEffects.TAUNT.get())
|
|
&& !MentalControlUtil.isMentalControlResistant(mob)
|
|
? ControlEffectHelper.validTauntSource(mob) : null;
|
|
if (taunter != null) {
|
|
if (event.getNewTarget() != taunter) event.setNewTarget(taunter);
|
|
return;
|
|
}
|
|
if (mob.hasEffect(ModEffects.CHARM.get()) && event.getNewTarget() != null
|
|
&& ControlEffectHelper.isOwnCharmSource(mob, event.getNewTarget())) event.setNewTarget(null);
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public static void onHurt(LivingHurtEvent event) {
|
|
if (event.isCanceled()) return;
|
|
LivingEntity victim = event.getEntity();
|
|
DamageSource damageSource = event.getSource();
|
|
Entity causing = damageSource.getEntity();
|
|
LivingEntity attacker = causing instanceof LivingEntity living ? living : null;
|
|
float amount = event.getAmount();
|
|
|
|
// 1. Victim vulnerability.
|
|
if (victim.hasEffect(ModEffects.SOUL_ROT.get()))
|
|
amount *= (float) AilmentsConfig.value(AilmentsConfig.SOUL_ROT_DAMAGE_TAKEN);
|
|
|
|
// 2. Charm victim and attacker rules.
|
|
if (attacker != null && !(victim instanceof Player) && victim.hasEffect(ModEffects.CHARM.get())
|
|
&& ControlEffectHelper.isOwnCharmSource(victim, attacker))
|
|
amount *= (float) AilmentsConfig.value(AilmentsConfig.CHARM_VICTIM_BONUS);
|
|
if (attacker != null && attacker.hasEffect(ModEffects.CHARM.get())) {
|
|
amount *= (float) (ControlEffectHelper.isOwnCharmSource(attacker, victim)
|
|
? AilmentsConfig.value(AilmentsConfig.CHARM_SOURCE_PENALTY)
|
|
: AilmentsConfig.value(AilmentsConfig.CHARM_OTHER_BONUS));
|
|
}
|
|
|
|
// 3. Taunt rules; each logically distinct rule is applied once.
|
|
if (victim.hasEffect(ModEffects.TAUNT.get()))
|
|
amount *= (float) AilmentsConfig.value(AilmentsConfig.TAUNT_VICTIM_MULTIPLIER);
|
|
if (attacker != null && attacker.hasEffect(ModEffects.TAUNT.get())) {
|
|
LivingEntity taunter = EffectSourceUtil.getSource(attacker, EffectSourceUtil.TAUNT);
|
|
if (taunter != null && taunter.getUUID().equals(victim.getUUID()))
|
|
amount *= (float) AilmentsConfig.value(AilmentsConfig.TAUNT_SOURCE_MULTIPLIER);
|
|
}
|
|
|
|
// 4. Snapshot pre-hit Charm before Overcharm refreshes it.
|
|
if (attacker != null && attacker != victim && attacker.hasEffect(ModEffects.OVERCHARM.get())) {
|
|
boolean alreadyCharmedByAttacker = victim.hasEffect(ModEffects.CHARM.get())
|
|
&& ControlEffectHelper.isOwnCharmSource(victim, attacker);
|
|
boolean directPlayerMelee = attacker instanceof Player && damageSource.getDirectEntity() == attacker;
|
|
if (alreadyCharmedByAttacker && directPlayerMelee)
|
|
amount *= (float) AilmentsConfig.value(AilmentsConfig.OVERCHARM_DAMAGE_BONUS);
|
|
AilmentApi.applyCharm(victim, attacker,
|
|
AilmentsConfig.value(AilmentsConfig.OVERCHARM_CHARM_DURATION));
|
|
}
|
|
|
|
if (attacker != null && attacker != victim && amount > 0
|
|
&& damageSource.getDirectEntity() == attacker)
|
|
applyTaggedWeaponAilments(attacker.getMainHandItem(), victim, attacker);
|
|
event.setAmount(amount);
|
|
}
|
|
|
|
private static void applyTaggedWeaponAilments(ItemStack stack, LivingEntity victim, LivingEntity attacker) {
|
|
if (stack.isEmpty()) return;
|
|
if (isAutomaticBleedWeapon(stack) && attacker.getRandom().nextDouble()
|
|
< AilmentsConfig.value(AilmentsConfig.AUTOMATIC_WEAPON_BLEED_CHANCE))
|
|
AilmentApi.applyBleed(victim, attacker);
|
|
if (stack.is(ModItemTags.SOUL_ROT_ON_HIT)) AilmentApi.applySoulRot(victim, attacker);
|
|
if (stack.is(ModItemTags.FRACTURE_ON_HIT)) AilmentApi.applyFracture(victim, attacker);
|
|
|
|
int duration = AilmentsConfig.value(AilmentsConfig.TAGGED_WEAPON_EFFECT_DURATION);
|
|
if (stack.is(ModItemTags.FEAR_ON_HIT)) AilmentApi.applyFear(victim, attacker, duration);
|
|
if (stack.is(ModItemTags.CHARM_ON_HIT)) AilmentApi.applyCharm(victim, attacker, duration);
|
|
if (stack.is(ModItemTags.TAUNT_ON_HIT)) AilmentApi.applyTaunt(victim, attacker, duration, 0);
|
|
if (stack.is(ModItemTags.OVERCHARM_ON_HIT)) AilmentApi.applyOvercharm(victim, attacker, duration);
|
|
if (stack.is(ModItemTags.WINDED_ON_HIT)) AilmentApi.applyWinded(victim, attacker, duration);
|
|
}
|
|
|
|
private static boolean isAutomaticBleedWeapon(ItemStack stack) {
|
|
if (!AilmentsConfig.value(AilmentsConfig.AUTOMATIC_WEAPON_BLEED) || stack.isEmpty()) return false;
|
|
if (stack.is(ModItemTags.BLEED_ON_HIT)) return true;
|
|
ResourceLocation id = ForgeRegistries.ITEMS.getKey(stack.getItem());
|
|
if (id == null || id.getNamespace().equals("minecraft")) return false;
|
|
String path = id.getPath().toLowerCase(Locale.ROOT);
|
|
return AilmentsConfig.weaponBleedKeywords().stream()
|
|
.map(keyword -> keyword.toLowerCase(Locale.ROOT))
|
|
.anyMatch(path::contains);
|
|
}
|
|
private AilmentEvents() {}
|
|
}
|