superb-warfare/src/main/java/com/atsuishio/superbwarfare/event/LivingEventHandler.java
2025-04-05 17:50:49 +08:00

887 lines
36 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.atsuishio.superbwarfare.event;
import com.atsuishio.superbwarfare.capability.ModCapabilities;
import com.atsuishio.superbwarfare.capability.player.PlayerVariable;
import com.atsuishio.superbwarfare.config.common.GameplayConfig;
import com.atsuishio.superbwarfare.config.server.MiscConfig;
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
import com.atsuishio.superbwarfare.entity.ICustomKnockback;
import com.atsuishio.superbwarfare.entity.TargetEntity;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.entity.vehicle.LaserTowerEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ContainerMobileVehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity;
import com.atsuishio.superbwarfare.event.events.PreKillEvent;
import com.atsuishio.superbwarfare.init.*;
import com.atsuishio.superbwarfare.item.gun.GunData;
import com.atsuishio.superbwarfare.item.gun.GunItem;
import com.atsuishio.superbwarfare.network.message.receive.ClientIndicatorMessage;
import com.atsuishio.superbwarfare.network.message.receive.DrawClientMessage;
import com.atsuishio.superbwarfare.network.message.receive.PlayerGunKillMessage;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkHelper;
import com.atsuishio.superbwarfare.tools.*;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundStopSoundPacket;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.block.entity.HopperBlockEntity;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.util.TriState;
import net.neoforged.neoforge.event.entity.living.*;
import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import java.util.Objects;
@EventBusSubscriber
public class LivingEventHandler {
@SubscribeEvent
public static void onEntityAttacked(LivingIncomingDamageEvent event) {
if (!event.getSource().is(ModDamageTypes.VEHICLE_EXPLOSION) && event.getEntity().getVehicle() instanceof VehicleEntity vehicle) {
if (event.getEntity().getVehicle() instanceof ArmedVehicleEntity iArmedVehicle && iArmedVehicle.hidePassenger(event.getEntity())) {
if (!(event.getSource().is(DamageTypes.EXPLOSION)
|| event.getSource().is(DamageTypes.PLAYER_EXPLOSION)
|| event.getSource().is(ModDamageTypes.CUSTOM_EXPLOSION)
|| event.getSource().is(ModDamageTypes.MINE)
|| event.getSource().is(ModDamageTypes.PROJECTILE_BOOM))) {
vehicle.hurt(event.getSource(), event.getContainer().getOriginalDamage());
}
event.setCanceled(true);
}
}
}
@SubscribeEvent
public static void onEntityHurt(LivingIncomingDamageEvent event) {
if (event == null) return;
handleVehicleHurt(event);
handleGunPerksWhenHurt(event);
renderDamageIndicator(event);
reduceBulletDamage(event);
giveExpToWeapon(event);
handleGunLevels(event);
}
@SubscribeEvent
public static void onEntityDeath(LivingDeathEvent event) {
if (event == null) return;
killIndication(event);
handleGunPerksWhenDeath(event);
handlePlayerKillEntity(event);
handlePlayerDeathDropAmmo(event.getEntity());
giveKillExpToWeapon(event);
if (event.getEntity() instanceof Player player) {
handlePlayerBeamReset(player);
}
}
private static void handleVehicleHurt(LivingIncomingDamageEvent event) {
var vehicle = event.getEntity().getVehicle();
if (vehicle instanceof VehicleEntity) {
if (vehicle instanceof ArmedVehicleEntity iArmedVehicle) {
if (iArmedVehicle.hidePassenger(event.getEntity())) {
if (!event.getSource().is(ModDamageTypes.VEHICLE_EXPLOSION)) {
event.setCanceled(true);
}
} else {
if (!(event.getSource().is(DamageTypes.EXPLOSION)
|| event.getSource().is(DamageTypes.PLAYER_EXPLOSION)
|| event.getSource().is(ModDamageTypes.CUSTOM_EXPLOSION)
|| event.getSource().is(ModDamageTypes.MINE)
|| event.getSource().is(ModDamageTypes.PROJECTILE_BOOM))) {
vehicle.hurt(event.getSource(), 0.7f * event.getAmount());
}
event.setAmount(0.3f * event.getAmount());
}
}
}
}
/**
* 计算子弹伤害衰减
*/
private static void reduceBulletDamage(LivingIncomingDamageEvent event) {
DamageSource source = event.getSource();
LivingEntity entity = event.getEntity();
Entity sourceEntity = source.getEntity();
if (sourceEntity == null) return;
double amount = event.getAmount();
double damage = amount;
ItemStack stack = sourceEntity instanceof LivingEntity living ? living.getMainHandItem() : ItemStack.EMPTY;
final var tag = NBTTool.getTag(stack);
var perk = PerkHelper.getPerkByType(tag, Perk.Type.AMMO);
// 距离衰减
if (DamageTypeTool.isGunDamage(source)) {
double distance = entity.position().distanceTo(sourceEntity.position());
if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) {
if (perk instanceof AmmoPerk ammoPerk && ammoPerk.slug) {
damage = reduceDamageByDistance(amount, distance, 0.015, 30);
} else {
damage = reduceDamageByDistance(amount, distance, 0.05, 15);
}
} else if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) {
damage = reduceDamageByDistance(amount, distance, 0.001, 150);
} else if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) {
damage = reduceDamageByDistance(amount, distance, 0.0007, 250);
} else if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) {
damage = reduceDamageByDistance(amount, distance, 0.03, 40);
} else if (stack.is(ModTags.Items.SMG)) {
damage = reduceDamageByDistance(amount, distance, 0.02, 50);
} else if (stack.is(ModTags.Items.USE_RIFLE_AMMO) || stack.getItem() == ModItems.BOCEK.get()) {
damage = reduceDamageByDistance(amount, distance, 0.007, 100);
}
}
// 计算防弹插板减伤
ItemStack armor = entity.getItemBySlot(EquipmentSlot.CHEST);
if (armor != ItemStack.EMPTY && tag.contains("ArmorPlate")) {
double armorValue;
armorValue = tag.getDouble("ArmorPlate");
tag.putDouble("ArmorPlate", Math.max(tag.getDouble("ArmorPlate") - damage, 0));
NBTTool.saveTag(stack, tag);
damage = Math.max(damage - armorValue, 0);
}
// 计算防弹护具减伤
if (source.is(ModTags.DamageTypes.PROJECTILE) || source.is(DamageTypes.MOB_PROJECTILE)) {
damage *= 1 - 0.8 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1);
}
if (source.is(ModTags.DamageTypes.PROJECTILE_ABSOLUTE)) {
damage *= 1 - 0.2 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1);
}
if (source.is(ModDamageTypes.PROJECTILE_BOOM) || source.is(ModDamageTypes.MINE) || source.is(ModDamageTypes.CANNON_FIRE) || source.is(ModDamageTypes.CUSTOM_EXPLOSION)
|| source.is(DamageTypes.EXPLOSION) || source.is(DamageTypes.PLAYER_EXPLOSION)) {
damage *= 1 - 0.3 * Mth.clamp(entity.getAttributeValue(ModAttributes.BULLET_RESISTANCE), 0, 1);
}
event.setAmount((float) damage);
if (entity instanceof TargetEntity && sourceEntity instanceof Player player) {
player.displayClientMessage(Component.translatable("tips.superbwarfare.target.damage",
FormatTool.format2D(damage),
FormatTool.format1D(entity.position().distanceTo(sourceEntity.position())), "m"), false);
}
}
private static double reduceDamageByDistance(double amount, double distance, double rate, double minDistance) {
return amount / (1 + rate * Math.max(0, distance - minDistance));
}
/**
* 根据造成的伤害,提供武器经验
*/
private static void giveExpToWeapon(LivingIncomingDamageEvent event) {
DamageSource source = event.getSource();
Entity sourceEntity = source.getEntity();
if (!(sourceEntity instanceof Player player)) return;
ItemStack stack = player.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) return;
if (event.getEntity() instanceof TargetEntity) return;
var data = GunData.from(stack);
double amount = Math.min(0.125 * event.getAmount(), event.getEntity().getMaxHealth());
final var tag = NBTTool.getTag(stack);
// 先处理发射器类武器或高爆弹的爆炸伤害
if (source.is(ModDamageTypes.PROJECTILE_BOOM)) {
if (stack.is(ModTags.Items.LAUNCHER) || PerkHelper.getItemPerkLevel(ModPerks.HE_BULLET.get(), tag) > 0) {
data.setExp(data.getExp() + amount);
}
}
// 再判断是不是枪械能造成的伤害
if (!DamageTypeTool.isGunDamage(source)) return;
data.setExp(data.getExp() + amount);
data.save();
}
private static void giveKillExpToWeapon(LivingDeathEvent event) {
DamageSource source = event.getSource();
Entity sourceEntity = source.getEntity();
if (!(sourceEntity instanceof Player player)) return;
ItemStack stack = player.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) return;
if (event.getEntity() instanceof TargetEntity) return;
var data = GunData.from(stack);
double amount = 20 + 2 * event.getEntity().getMaxHealth();
final var tag = NBTTool.getTag(stack);
// 先处理发射器类武器或高爆弹的爆炸伤害
if (source.is(ModDamageTypes.PROJECTILE_BOOM)) {
if (stack.is(ModTags.Items.LAUNCHER) || PerkHelper.getItemPerkLevel(ModPerks.HE_BULLET.get(), tag) > 0) {
data.setExp(data.getExp() + amount);
}
}
// 再判断是不是枪械能造成的伤害
if (DamageTypeTool.isGunDamage(source)) {
data.setExp(data.getExp() + amount);
}
// 提升武器等级
int level = data.getLevel();
double exp = data.getExp();
double upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20;
while (exp >= upgradeExpNeeded) {
exp -= upgradeExpNeeded;
level = data.getLevel() + 1;
upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20;
data.setExp(exp);
data.setLevel(level);
data.setUpgradePoint(data.getUpgradePoint() + 0.5);
}
data.save();
}
private static void handleGunLevels(LivingIncomingDamageEvent event) {
DamageSource source = event.getSource();
Entity sourceEntity = source.getEntity();
if (!(sourceEntity instanceof Player player)) return;
ItemStack stack = player.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) return;
if (event.getEntity() instanceof TargetEntity) return;
var data = GunData.from(stack);
int level = data.getLevel();
double exp = data.getExp();
double upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20;
while (exp >= upgradeExpNeeded) {
exp -= upgradeExpNeeded;
level = data.getLevel() + 1;
upgradeExpNeeded = 20 * Math.pow(level, 2) + 160 * level + 20;
data.setExp(exp);
data.setLevel(level);
data.setUpgradePoint(data.getUpgradePoint() + 0.5);
}
data.save();
}
private static void killIndication(LivingDeathEvent event) {
DamageSource source = event.getSource();
var sourceEntity = source.getEntity();
if (sourceEntity == null) {
return;
}
// 如果配置不选择全局伤害提示则只在伤害类型为mod添加的时显示指示器
if (!GameplayConfig.GLOBAL_INDICATION.get() && !DamageTypeTool.isModDamage(source)) {
return;
}
if (!sourceEntity.level().isClientSide() && sourceEntity instanceof ServerPlayer player) {
// TODO 判断 pre kill event 结果
// if (NeoForge.EVENT_BUS.post(new PreKillEvent.Indicator(player, source, event.getEntity()))) {
// return;
// }
SoundTool.playLocalSound(player, ModSounds.TARGET_DOWN.get(), 3f, 1f);
PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(2, 8));
}
}
private static void renderDamageIndicator(LivingIncomingDamageEvent event) {
if (event == null) return;
var damagesource = event.getSource();
var sourceEntity = damagesource.getEntity();
if (sourceEntity == null) return;
if (sourceEntity instanceof ServerPlayer player && (damagesource.is(DamageTypes.EXPLOSION) || damagesource.is(DamageTypes.PLAYER_EXPLOSION)
|| damagesource.is(ModDamageTypes.MINE) || damagesource.is(ModDamageTypes.PROJECTILE_BOOM))) {
SoundTool.playLocalSound(player, ModSounds.INDICATION.get(), 1f, 1f);
PacketDistributor.sendToPlayer(player, new ClientIndicatorMessage(0, 5));
}
}
/**
* 换弹时切换枪械,取消换弹音效播放
*/
@SubscribeEvent
public static void handleChangeSlot(LivingEquipmentChangeEvent event) {
if (event.getEntity() instanceof Player player && event.getSlot() == EquipmentSlot.MAINHAND) {
if (player.level().isClientSide) return;
ItemStack oldStack = event.getFrom();
ItemStack newStack = event.getTo();
var laserCap = player.getCapability(ModCapabilities.LASER_CAPABILITY);
if (laserCap != null) laserCap.stop();
var oldTag = NBTTool.getTag(oldStack);
var newTag = NBTTool.getTag(newStack);
if (player instanceof ServerPlayer serverPlayer
&& (newStack.getItem() != oldStack.getItem()
|| (newStack.is(ModTags.Items.GUN) && !GunsTool.getGunData(newTag).hasUUID("UUID"))
|| (oldStack.is(ModTags.Items.GUN) && !GunsTool.getGunData(oldTag).hasUUID("UUID"))
|| (newStack.is(ModTags.Items.GUN) && oldStack.is(ModTags.Items.GUN) && !Objects.equals(GunsTool.getGunUUID(newTag), GunsTool.getGunUUID(oldTag)))
)) {
if (oldStack.getItem() instanceof GunItem oldGun) {
stopGunReloadSound(serverPlayer, oldGun);
var oldData = GunData.from(oldStack);
oldTag = oldData.getTag();
var data = oldData.getData();
if (oldData.boltActionTime() > 0) {
data.putInt("BoltActionTick", 0);
}
data.putInt("ReloadTime", 0);
oldTag.put("GunData", data);
oldData.setReloadState(GunData.ReloadState.NOT_RELOADING);
if (oldData.iterativeTime() != 0) {
oldTag.putBoolean("force_stop", false);
oldTag.putBoolean("stop", false);
oldData.setReloadStage(0);
oldTag.putDouble("prepare", 0);
oldTag.putDouble("prepare_load", 0);
oldTag.putDouble("iterative", 0);
oldTag.putDouble("finish", 0);
}
if (oldStack.is(ModItems.SENTINEL.get())) {
data.putBoolean("Charging", false);
data.putInt("ChargeTime", 0);
}
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap != null) {
cap.edit = false;
cap.syncPlayerVariables(player);
}
oldData.save();
}
if (newStack.getItem() instanceof GunItem) {
var newData = GunData.from(newStack);
newTag = newData.getTag();
player.getPersistentData().putDouble("noRun", 40);
newTag.putBoolean("draw", true);
if (newData.boltActionTime() > 0) {
GunsTool.setGunIntTag(newTag, "BoltActionTick", 0);
}
newData.setReloadState(GunData.ReloadState.NOT_RELOADING);
var data = newTag.getCompound("GunData");
data.putInt("ReloadTime", 0);
newTag.put("GunData", data);
if (newData.iterativeTime() != 0) {
newTag.putBoolean("force_stop", false);
newTag.putBoolean("stop", false);
newData.setReloadStage(0);
newTag.putDouble("prepare", 0);
newTag.putDouble("prepare_load", 0);
newTag.putDouble("iterative", 0);
newTag.putDouble("finish", 0);
}
if (newStack.is(ModItems.SENTINEL.get())) {
GunsTool.setGunBooleanTag(newTag, "Charging", false);
GunsTool.setGunIntTag(newTag, "ChargeTime", 0);
}
int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), newTag);
if (level != 0) {
GunsTool.setPerkIntTag(newTag, "KillingTally", 0);
}
if (player.level() instanceof ServerLevel) {
PacketDistributor.sendToPlayer(serverPlayer, new DrawClientMessage(true));
}
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap != null) {
cap.tacticalSprint = false;
cap.syncPlayerVariables(player);
}
newData.save();
}
}
}
}
private static void stopGunReloadSound(ServerPlayer player, GunItem gun) {
gun.getReloadSound().forEach(sound -> {
var clientboundstopsoundpacket = new ClientboundStopSoundPacket(sound.getLocation(), SoundSource.PLAYERS);
player.connection.send(clientboundstopsoundpacket);
});
}
/**
* 发送击杀消息
*/
private static void handlePlayerKillEntity(LivingDeathEvent event) {
LivingEntity entity = event.getEntity();
DamageSource source = event.getSource();
ResourceKey<DamageType> damageTypeResourceKey = source.typeHolder().unwrapKey().isPresent() ? source.typeHolder().unwrapKey().get() : DamageTypes.GENERIC;
ServerPlayer attacker = null;
if (source.getEntity() instanceof ServerPlayer player) {
attacker = player;
}
if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof ServerPlayer player) {
attacker = player;
}
// TODO pre kill event
// if (NeoForge.EVENT_BUS.post(new PreKillEvent.SendKillMessage(attacker, source, entity))) {
// return;
// }
if (attacker != null && MiscConfig.SEND_KILL_FEEDBACK.get()) {
if (DamageTypeTool.isHeadshotDamage(source)) {
PacketDistributor.sendToAllPlayers(new PlayerGunKillMessage(attacker.getId(), entity.getId(), true, damageTypeResourceKey));
} else {
PacketDistributor.sendToAllPlayers(new PlayerGunKillMessage(attacker.getId(), entity.getId(), false, damageTypeResourceKey));
}
}
}
private static void handleGunPerksWhenHurt(LivingIncomingDamageEvent event) {
DamageSource source = event.getSource();
Player attacker = null;
if (source.getEntity() instanceof Player player) {
attacker = player;
}
if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof Player player) {
attacker = player;
}
if (attacker == null) {
return;
}
ItemStack stack = attacker.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) {
return;
}
if (DamageTypeTool.isGunDamage(source) || source.is(ModDamageTypes.PROJECTILE_BOOM)) {
handleKillClipDamage(stack, event);
handleVorpalWeaponDamage(stack, event);
}
if (DamageTypeTool.isGunFireDamage(source) && source.getDirectEntity() instanceof ProjectileEntity projectile && projectile.isZoom()) {
handleGutshotStraightDamage(stack, event);
}
if (DamageTypeTool.isGunDamage(source)) {
handleKillingTallyDamage(stack, event);
}
if (DamageTypeTool.isGunFireDamage(source)) {
handleHeadSeekerTime(stack);
}
if (source.getDirectEntity() instanceof ProjectileEntity projectile) {
final var tag = NBTTool.getTag(stack);
if (PerkHelper.getItemPerkLevel(ModPerks.FOURTH_TIMES_CHARM.get(), tag) > 0) {
float bypassArmorRate = projectile.getBypassArmorRate();
if (bypassArmorRate >= 1.0f && source.is(ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE)) {
handleFourthTimesCharm(stack);
} else if (source.is(ModDamageTypes.GUN_FIRE_HEADSHOT)) {
handleFourthTimesCharm(stack);
}
}
if (!projectile.isZoom()) {
handleFieldDoctor(stack, event, attacker);
}
}
if (DamageTypeTool.isHeadshotDamage(source)) {
handleHeadSeekerDamage(stack, event);
}
}
private static void handleGunPerksWhenDeath(LivingDeathEvent event) {
DamageSource source = event.getSource();
Player attacker = null;
if (source.getEntity() instanceof Player player) {
attacker = player;
}
if (source.getDirectEntity() instanceof Projectile projectile && projectile.getOwner() instanceof Player player) {
attacker = player;
}
if (attacker == null) {
return;
}
ItemStack stack = attacker.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) {
return;
}
if (DamageTypeTool.isGunDamage(source) || source.is(ModDamageTypes.PROJECTILE_BOOM)) {
handleClipPerks(stack);
}
if (DamageTypeTool.isGunDamage(source)) {
handleKillingTallyAddCount(stack);
handleSubsistence(stack, attacker);
}
if (DamageTypeTool.isHeadshotDamage(source)) {
handleDesperado(stack);
}
}
private static void handleClipPerks(ItemStack stack) {
var data = GunData.from(stack);
final var tag = data.getTag();
int healClipLevel = PerkHelper.getItemPerkLevel(ModPerks.HEAL_CLIP.get(), tag);
if (healClipLevel != 0) {
GunsTool.setPerkIntTag(tag, "HealClipTime", 80 + healClipLevel * 20);
}
int killClipLevel = PerkHelper.getItemPerkLevel(ModPerks.KILL_CLIP.get(), tag);
if (killClipLevel != 0) {
GunsTool.setPerkIntTag(tag, "KillClipReloadTime", 80);
}
data.save();
}
private static void handleKillClipDamage(ItemStack stack, LivingIncomingDamageEvent event) {
var data = GunData.from(stack);
final var tag = data.getTag();
if (GunsTool.getPerkIntTag(tag, "KillClipTime") > 0) {
int level = PerkHelper.getItemPerkLevel(ModPerks.KILL_CLIP.get(), tag);
if (level == 0) {
return;
}
event.setAmount(event.getAmount() * (1.2f + 0.05f * level));
}
}
private static void handleGutshotStraightDamage(ItemStack stack, LivingIncomingDamageEvent event) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.GUTSHOT_STRAIGHT.get(), tag);
if (level == 0) return;
event.setAmount(event.getAmount() * (1.15f + 0.05f * level));
}
private static void handleKillingTallyDamage(ItemStack stack, LivingIncomingDamageEvent event) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), tag);
if (level == 0) return;
int killTally = GunsTool.getPerkIntTag(tag, "KillingTally");
if (killTally == 0) {
return;
}
event.setAmount(event.getAmount() * (1.0f + (0.1f * level) * killTally));
}
private static void handleKillingTallyAddCount(ItemStack stack) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.KILLING_TALLY.get(), tag);
if (level != 0) {
GunsTool.setPerkIntTag(tag, "KillingTally", Math.min(3, GunsTool.getPerkIntTag(tag, "KillingTally") + 1));
data.save();
}
}
private static void handleFourthTimesCharm(ItemStack stack) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.FOURTH_TIMES_CHARM.get(), tag);
if (level == 0) return;
int fourthTimesCharmTick = GunsTool.getPerkIntTag(tag, "FourthTimesCharmTick");
if (fourthTimesCharmTick <= 0) {
GunsTool.setPerkIntTag(tag, "FourthTimesCharmTick", 40 + 10 * level);
GunsTool.setPerkIntTag(tag, "FourthTimesCharmCount", 1);
} else {
int count = GunsTool.getPerkIntTag(tag, "FourthTimesCharmCount");
if (count < 4) {
GunsTool.setPerkIntTag(tag, "FourthTimesCharmCount", Math.min(4, count + 1));
}
}
data.save();
}
private static void handleSubsistence(ItemStack stack, Player player) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.SUBSISTENCE.get(), tag);
if (level == 0) return;
float rate = level * 0.1f + (stack.is(ModTags.Items.SMG) || stack.is(ModTags.Items.RIFLE) ? 0.07f : 0f);
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap == null) return;
int mag = data.magazine();
int ammo = data.getAmmo();
int ammoReload = (int) Math.min(mag, mag * rate);
int ammoNeed = Math.min(mag - ammo, ammoReload);
boolean flag = InventoryTool.hasCreativeAmmoBox(player);
if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) {
int ammoFinal = Math.min(cap.rifleAmmo, ammoNeed);
if (flag) {
ammoFinal = ammoNeed;
} else {
cap.rifleAmmo -= ammoFinal;
}
data.setAmmo(Math.min(mag, ammo + ammoFinal));
} else if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) {
int ammoFinal = Math.min(cap.handgunAmmo, ammoNeed);
if (flag) {
ammoFinal = ammoNeed;
} else {
cap.handgunAmmo -= ammoFinal;
}
data.setAmmo(Math.min(mag, ammo + ammoFinal));
}
data.save();
cap.syncPlayerVariables(player);
}
private static void handleFieldDoctor(ItemStack stack, LivingIncomingDamageEvent event, Player player) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.FIELD_DOCTOR.get(), tag);
if (level == 0) return;
if (event.getEntity().isAlliedTo(player)) {
event.getEntity().heal(event.getAmount() * Math.min(1.0f, 0.25f + 0.05f * level));
event.setCanceled(true);
}
}
private static void handleHeadSeekerTime(ItemStack stack) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.HEAD_SEEKER.get(), tag);
if (level == 0) return;
GunsTool.setPerkIntTag(tag, "HeadSeeker", 11 + level * 2);
data.save();
}
private static void handleHeadSeekerDamage(ItemStack stack, LivingIncomingDamageEvent event) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.HEAD_SEEKER.get(), tag);
if (level == 0) return;
if (GunsTool.getPerkIntTag(tag, "HeadSeeker") > 0) {
event.setAmount(event.getAmount() * (1.095f + 0.0225f * level));
}
}
private static void handleDesperado(ItemStack stack) {
var data = GunData.from(stack);
final var tag = data.getTag();
int level = PerkHelper.getItemPerkLevel(ModPerks.DESPERADO.get(), tag);
if (level == 0) return;
GunsTool.setPerkIntTag(tag, "DesperadoTime", 90 + level * 10);
data.save();
}
/**
* 开启死亡掉落时掉落一个弹药盒
*/
private static void handlePlayerDeathDropAmmo(LivingEntity entity) {
if (!entity.level().getLevelData().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && entity instanceof Player player) {
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE);
if (cap == null) cap = new PlayerVariable();
boolean drop = cap.rifleAmmo + cap.handgunAmmo + cap.shotgunAmmo + cap.sniperAmmo + cap.heavyAmmo > 0;
if (drop) {
ItemStack stack = new ItemStack(ModItems.AMMO_BOX.get());
CompoundTag tag = NBTTool.getTag(stack);
for (var type : AmmoType.values()) {
type.set(tag, type.get(cap));
type.set(cap, 0);
}
tag.putBoolean("IsDrop", true);
NBTTool.saveTag(stack, tag);
cap.syncPlayerVariables(player);
if (player.level() instanceof ServerLevel level) {
ItemEntity itemEntity = new ItemEntity(level, player.getX(), player.getY() + 1, player.getZ(), stack);
itemEntity.setPickUpDelay(10);
level.addFreshEntity(itemEntity);
}
}
}
}
@SubscribeEvent
public static void onPickup(ItemEntityPickupEvent.Pre event) {
if (!VehicleConfig.VEHICLE_ITEM_PICKUP.get()) return;
if (event.getPlayer().getVehicle() instanceof ContainerMobileVehicleEntity containerMobileVehicleEntity) {
var pickUp = event.getItemEntity();
if (!containerMobileVehicleEntity.level().isClientSide) {
HopperBlockEntity.addItem(containerMobileVehicleEntity, pickUp);
}
event.setCanPickup(TriState.FALSE);
}
}
@SubscribeEvent
public static void onLivingDrops(LivingDropsEvent event) {
DamageSource source = event.getSource();
Entity sourceEntity = source.getEntity();
if (!(sourceEntity instanceof Player player)) return;
ItemStack stack = player.getMainHandItem();
if (player.getVehicle() instanceof ContainerMobileVehicleEntity containerMobileVehicleEntity && source.is(ModDamageTypes.VEHICLE_STRIKE)) {
var drops = event.getDrops();
drops.forEach(itemEntity -> {
ItemStack item = itemEntity.getItem();
if (!HopperBlockEntity.addItem(containerMobileVehicleEntity, itemEntity)) {
player.drop(item, false);
}
});
event.setCanceled(true);
return;
}
final var tag = NBTTool.getTag(stack);
if (stack.is(ModTags.Items.GUN) && PerkHelper.getItemPerkLevel(ModPerks.POWERFUL_ATTRACTION.get(), tag) > 0 && (DamageTypeTool.isGunDamage(source) || DamageTypeTool.isExplosionDamage(source))) {
var drops = event.getDrops();
drops.forEach(itemEntity -> {
ItemStack item = itemEntity.getItem();
if (!player.addItem(item)) {
player.drop(item, false);
}
});
event.setCanceled(true);
}
}
@SubscribeEvent
public static void onLivingExperienceDrop(LivingExperienceDropEvent event) {
Player player = event.getAttackingPlayer();
if (player == null) return;
if (player.getVehicle() instanceof ArmedVehicleEntity) {
player.giveExperiencePoints(event.getDroppedExperience());
event.setCanceled(true);
return;
}
ItemStack stack = player.getMainHandItem();
if (!stack.is(ModTags.Items.GUN)) return;
final var tag = NBTTool.getTag(stack);
int level = PerkHelper.getItemPerkLevel(ModPerks.POWERFUL_ATTRACTION.get(), tag);
if (level > 0) {
player.giveExperiencePoints((int) (event.getDroppedExperience() * (0.8f + 0.2f * level)));
event.setCanceled(true);
}
}
public static void handlePlayerBeamReset(Player player) {
var cap = player.getCapability(ModCapabilities.LASER_CAPABILITY);
if (cap != null) {
cap.end();
}
}
private static void handleVorpalWeaponDamage(ItemStack stack, LivingIncomingDamageEvent event) {
var entity = event.getEntity();
final var tag = NBTTool.getTag(stack);
int level = PerkHelper.getItemPerkLevel(ModPerks.VORPAL_WEAPON.get(), tag);
if (level <= 0) return;
if (entity.getHealth() < 100.0f) return;
event.setAmount((float) (event.getAmount() + entity.getHealth() * 0.00002f * Math.pow(level, 2)));
}
@SubscribeEvent
public static void onKnockback(LivingKnockBackEvent event) {
ICustomKnockback knockback = ICustomKnockback.getInstance(event.getEntity());
if (knockback.superbWarfare$getKnockbackStrength() >= 0) {
event.setStrength((float) knockback.superbWarfare$getKnockbackStrength());
}
}
@SubscribeEvent
public static void onEntityFall(LivingFallEvent event) {
LivingEntity living = event.getEntity();
if (living.getVehicle() instanceof VehicleEntity) {
event.setCanceled(true);
}
}
@SubscribeEvent
public static void onPreSendKillMessage(PreKillEvent.SendKillMessage event) {
if (event.getSource().getDirectEntity() instanceof LaserTowerEntity && !(event.getTarget() instanceof Player)) {
event.setCanceled(true);
}
}
@SubscribeEvent
public static void onPreIndicator(PreKillEvent.Indicator event) {
if (event.getSource().getDirectEntity() instanceof LaserTowerEntity && !(event.getTarget() instanceof Player)) {
event.setCanceled(true);
}
}
}