mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-03-11 12:15:35 +00:00
504 lines
18 KiB
Java
504 lines
18 KiB
Java
package com.hbm.util;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.util.List;
|
|
|
|
import com.hbm.config.ServerConfig;
|
|
|
|
import cpw.mods.fml.relauncher.ReflectionHelper;
|
|
import net.minecraft.enchantment.EnchantmentHelper;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.entity.SharedMonsterAttributes;
|
|
import net.minecraft.entity.passive.EntityTameable;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.potion.Potion;
|
|
import net.minecraft.util.AxisAlignedBB;
|
|
import net.minecraft.util.DamageSource;
|
|
import net.minecraft.util.MovingObjectPosition;
|
|
import net.minecraft.util.Vec3;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.common.ForgeHooks;
|
|
|
|
public class EntityDamageUtil {
|
|
|
|
/** Shitty hack, if the first attack fails, it retries with damage + previous damage, allowing damage to penetrate */
|
|
@Deprecated public static boolean attackEntityFromIgnoreIFrame(Entity victim, DamageSource src, float damage) {
|
|
|
|
if(!victim.attackEntityFrom(src, damage)) {
|
|
|
|
if(victim instanceof EntityLivingBase) {
|
|
EntityLivingBase living = (EntityLivingBase) victim;
|
|
|
|
if(living.hurtResistantTime > living.maxHurtResistantTime / 2.0F) {
|
|
damage += living.lastDamage;
|
|
}
|
|
}
|
|
return victim.attackEntityFrom(src, damage);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/** New and improved entity damage calc - only use this one */
|
|
public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier, float pierceDT, float pierce) {
|
|
if(living instanceof EntityPlayerMP && source.getEntity() instanceof EntityPlayer) {
|
|
EntityPlayerMP playerMP = (EntityPlayerMP) living;
|
|
EntityPlayer attacker = (EntityPlayer) source.getEntity();
|
|
if(!playerMP.canAttackPlayer(attacker)) return false; //handles wack-ass no PVP rule as well as scoreboard friendly fire
|
|
}
|
|
DamageResistanceHandler.setup(pierceDT, pierce);
|
|
boolean ret = attackEntityFromNTInternal(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier);
|
|
DamageResistanceHandler.reset();
|
|
return ret;
|
|
}
|
|
|
|
private static boolean attackEntityFromNTInternal(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) {
|
|
boolean superCompatibility = ServerConfig.DAMAGE_COMPATIBILITY_MODE.get();
|
|
return superCompatibility
|
|
? attackEntitySuperCompatibility(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier)
|
|
: attackEntitySEDNAPatch(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier);
|
|
}
|
|
|
|
/**
|
|
* MK2 SEDNA damage system, currently untested. An even hackier, yet more compatible solution using the vanilla damage calc directly but tweaking certain apsects.
|
|
* Limitation: Does not apply DR piercing to vanilla armor
|
|
*/
|
|
private static boolean attackEntitySuperCompatibility(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) {
|
|
//disable iframes
|
|
if(ignoreIFrame) { living.lastDamage = 0F; living.hurtResistantTime = 0; }
|
|
//cache last velocity
|
|
double motionX = living.motionX;
|
|
double motionY = living.motionX;
|
|
double motionZ = living.motionX;
|
|
//bam!
|
|
boolean ret = living.attackEntityFrom(source, amount);
|
|
//restore last velocity
|
|
living.motionX = motionX;
|
|
living.motionY = motionY;
|
|
living.motionZ = motionZ;
|
|
//apply own knockback
|
|
Entity entity = source.getEntity();
|
|
if(entity != null) {
|
|
double deltaX = entity.posX - living.posX;
|
|
double deltaZ;
|
|
|
|
for(deltaZ = entity.posZ - living.posZ; deltaX * deltaX + deltaZ * deltaZ < 1.0E-4D; deltaZ = (Math.random() - Math.random()) * 0.01D) {
|
|
deltaX = (Math.random() - Math.random()) * 0.01D;
|
|
}
|
|
|
|
living.attackedAtYaw = (float) (Math.atan2(deltaZ, deltaX) * 180.0D / Math.PI) - living.rotationYaw;
|
|
if(knockbackMultiplier > 0) knockBack(living, entity, amount, deltaX, deltaZ, knockbackMultiplier);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/** MK1 SEDNA damage system, basically re-implements the vanilla code (only from Entity, child class code is effectively ignored) with some adjustments */
|
|
private static boolean attackEntitySEDNAPatch(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) {
|
|
living.attackEntityFrom(source, 0F);
|
|
if(ignoreIFrame) living.lastDamage = 0F;
|
|
if(ForgeHooks.onLivingAttack(living, source, amount) && allowSpecialCancel) return false;
|
|
if(living.isEntityInvulnerable()) return false;
|
|
if(living.worldObj.isRemote) return false;
|
|
if(living instanceof EntityPlayer && ((EntityPlayer) living).capabilities.disableDamage && !source.canHarmInCreative()) return false;
|
|
|
|
living.entityAge = 0;
|
|
if(living.getHealth() <= 0.0F) return false;
|
|
if(source.isFireDamage() && living.isPotionActive(Potion.fireResistance)) return false;
|
|
|
|
living.limbSwingAmount = 1.5F;
|
|
boolean didAttackRegister = true;
|
|
|
|
if(living.hurtResistantTime > living.maxHurtResistantTime / 2.0F && !ignoreIFrame) {
|
|
if(amount <= living.lastDamage) { return false; }
|
|
damageEntityNT(living, source, amount - living.lastDamage);
|
|
living.lastDamage = amount;
|
|
didAttackRegister = false;
|
|
} else {
|
|
living.lastDamage = amount;
|
|
living.prevHealth = living.getHealth();
|
|
living.hurtResistantTime = living.maxHurtResistantTime;
|
|
damageEntityNT(living, source, amount);
|
|
living.hurtTime = living.maxHurtTime = 10;
|
|
}
|
|
|
|
living.attackedAtYaw = 0.0F;
|
|
Entity entity = source.getEntity();
|
|
|
|
if(entity != null) {
|
|
if(entity instanceof EntityLivingBase) {
|
|
living.setRevengeTarget((EntityLivingBase) entity);
|
|
}
|
|
|
|
if(entity instanceof EntityPlayer) {
|
|
living.recentlyHit = 100;
|
|
living.attackingPlayer = (EntityPlayer) entity;
|
|
} else if(entity instanceof EntityTameable) {
|
|
EntityTameable entitywolf = (EntityTameable) entity;
|
|
|
|
if(entitywolf.isTamed()) {
|
|
living.recentlyHit = 100;
|
|
living.attackingPlayer = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(didAttackRegister) {
|
|
living.worldObj.setEntityState(living, (byte) 2);
|
|
|
|
if(source != DamageSource.drown) setBeenAttacked(living); //#
|
|
|
|
if(entity != null) {
|
|
double deltaX = entity.posX - living.posX;
|
|
double deltaZ;
|
|
|
|
for(deltaZ = entity.posZ - living.posZ; deltaX * deltaX + deltaZ * deltaZ < 1.0E-4D; deltaZ = (Math.random() - Math.random()) * 0.01D) {
|
|
deltaX = (Math.random() - Math.random()) * 0.01D;
|
|
}
|
|
|
|
living.attackedAtYaw = (float) (Math.atan2(deltaZ, deltaX) * 180.0D / Math.PI) - living.rotationYaw;
|
|
if(knockbackMultiplier > 0) knockBack(living, entity, amount, deltaX, deltaZ, knockbackMultiplier);
|
|
} else {
|
|
living.attackedAtYaw = (float) ((int) (Math.random() * 2.0D) * 180);
|
|
}
|
|
}
|
|
|
|
String sound;
|
|
|
|
if(living.getHealth() <= 0.0F) {
|
|
sound = getDeathSound(living);
|
|
if(didAttackRegister && sound != null) living.playSound(sound, getSoundVolume(living), getSoundPitch(living)); //#
|
|
living.onDeath(source);
|
|
} else {
|
|
sound = getHurtSound(living);
|
|
if(didAttackRegister && sound != null) living.playSound(sound, getSoundVolume(living), getSoundPitch(living)); //#
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static void knockBack(EntityLivingBase living, Entity attacker, float damage, double motionX, double motionZ, double multiplier) {
|
|
if(living.getRNG().nextDouble() >= living.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).getAttributeValue()) {
|
|
living.isAirBorne = true;
|
|
double horizontal = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
|
double magnitude = 0.4D * multiplier;
|
|
living.motionX /= 2.0D;
|
|
living.motionY /= 2.0D;
|
|
living.motionZ /= 2.0D;
|
|
living.motionX -= motionX / horizontal * magnitude;
|
|
living.motionY += (double) magnitude;
|
|
living.motionZ -= motionZ / horizontal * magnitude;
|
|
|
|
if(living.motionY > 0.2D) {
|
|
living.motionY = 0.2D * multiplier;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void damageEntityNT(EntityLivingBase living, DamageSource source, float amount) {
|
|
if(!living.isEntityInvulnerable()) {
|
|
amount = ForgeHooks.onLivingHurt(living, source, amount);
|
|
if(amount <= 0) return;
|
|
|
|
amount = applyArmorCalculationsNT(living, source, amount);
|
|
amount = applyPotionDamageCalculations(living, source, amount);
|
|
|
|
float originalAmount = amount;
|
|
amount = Math.max(amount - living.getAbsorptionAmount(), 0.0F);
|
|
living.setAbsorptionAmount(living.getAbsorptionAmount() - (originalAmount - amount));
|
|
|
|
if(amount != 0.0F) {
|
|
float health = living.getHealth();
|
|
living.setHealth(health - amount);
|
|
living.func_110142_aN().func_94547_a(source, health, amount);
|
|
living.setAbsorptionAmount(living.getAbsorptionAmount() - amount);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static float applyArmorCalculationsNT(EntityLivingBase living, DamageSource source, float amount) {
|
|
if(!source.isUnblockable()) {
|
|
float i = 25F - (living.getTotalArmorValue() * (1 - DamageResistanceHandler.currentPDR));
|
|
float armor = amount * (float) i;
|
|
damageArmorNT(living, amount);
|
|
amount = armor / 25.0F;
|
|
}
|
|
|
|
return amount;
|
|
}
|
|
|
|
public static void damageArmorNT(EntityLivingBase living, float amount) { }
|
|
|
|
/** Currently just a copy of the vanilla damage code */
|
|
@Deprecated public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount) {
|
|
|
|
if(ForgeHooks.onLivingAttack(living, source, amount))
|
|
return false;
|
|
if(living.isEntityInvulnerable()) {
|
|
return false;
|
|
} else if(living.worldObj.isRemote) {
|
|
return false;
|
|
} else {
|
|
living.entityAge = 0;
|
|
|
|
if(living.getHealth() <= 0.0F) {
|
|
return false;
|
|
} else if(source.isFireDamage() && living.isPotionActive(Potion.fireResistance)) {
|
|
return false;
|
|
} else {
|
|
if((source == DamageSource.anvil || source == DamageSource.fallingBlock) && living.getEquipmentInSlot(4) != null) {
|
|
living.getEquipmentInSlot(4).damageItem((int) (amount * 4.0F + living.getRNG().nextFloat() * amount * 2.0F), living);
|
|
amount *= 0.75F;
|
|
}
|
|
|
|
living.limbSwingAmount = 1.5F;
|
|
boolean flag = true;
|
|
|
|
if((float) living.hurtResistantTime > (float) living.maxHurtResistantTime / 2.0F) {
|
|
if(amount <= living.lastDamage) {
|
|
return false;
|
|
}
|
|
|
|
damageEntity(living, source, amount - living.lastDamage); //#
|
|
living.lastDamage = amount;
|
|
flag = false;
|
|
} else {
|
|
living.lastDamage = amount;
|
|
living.prevHealth = living.getHealth();
|
|
living.hurtResistantTime = living.maxHurtResistantTime;
|
|
damageEntity(living, source, amount); //#
|
|
living.hurtTime = living.maxHurtTime = 10;
|
|
}
|
|
|
|
living.attackedAtYaw = 0.0F;
|
|
Entity entity = source.getEntity();
|
|
|
|
if(entity != null) {
|
|
if(entity instanceof EntityLivingBase) {
|
|
living.setRevengeTarget((EntityLivingBase) entity);
|
|
}
|
|
|
|
if(entity instanceof EntityPlayer) {
|
|
living.recentlyHit = 100;
|
|
living.attackingPlayer = (EntityPlayer) entity;
|
|
} else if(entity instanceof EntityTameable) {
|
|
EntityTameable entitywolf = (EntityTameable) entity;
|
|
|
|
if(entitywolf.isTamed()) {
|
|
living.recentlyHit = 100;
|
|
living.attackingPlayer = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(flag) {
|
|
living.worldObj.setEntityState(living, (byte) 2);
|
|
|
|
if(source != DamageSource.drown) {
|
|
setBeenAttacked(living); //#
|
|
}
|
|
|
|
if(entity != null) {
|
|
double d1 = entity.posX - living.posX;
|
|
double d0;
|
|
|
|
for(d0 = entity.posZ - living.posZ; d1 * d1 + d0 * d0 < 1.0E-4D; d0 = (Math.random() - Math.random()) * 0.01D) {
|
|
d1 = (Math.random() - Math.random()) * 0.01D;
|
|
}
|
|
|
|
living.attackedAtYaw = (float) (Math.atan2(d0, d1) * 180.0D / Math.PI) - living.rotationYaw;
|
|
living.knockBack(entity, amount, d1, d0);
|
|
} else {
|
|
living.attackedAtYaw = (float) ((int) (Math.random() * 2.0D) * 180);
|
|
}
|
|
}
|
|
|
|
String s;
|
|
|
|
if(living.getHealth() <= 0.0F) {
|
|
s = getDeathSound(living); //#
|
|
|
|
if(flag && s != null) {
|
|
living.playSound(s, getSoundVolume(living), getSoundPitch(living)); //#
|
|
}
|
|
|
|
living.onDeath(source);
|
|
} else {
|
|
s = getHurtSound(living); //#
|
|
|
|
if(flag && s != null) {
|
|
living.playSound(s, getSoundVolume(living), getSoundPitch(living)); //#
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// in this household we drink gasoline and sniff glue
|
|
public static String getDeathSound(EntityLivingBase living) {
|
|
Method m = ReflectionHelper.findMethod(EntityLivingBase.class, living, new String[] {"func_70673_aS", "getDeathSound"});
|
|
try { return (String) m.invoke(living); } catch(Exception e) { } return "game.neutral.die";
|
|
}
|
|
|
|
public static String getHurtSound(EntityLivingBase living) {
|
|
Method m = ReflectionHelper.findMethod(EntityLivingBase.class, living, new String[] {"func_70621_aR", "getHurtSound"});
|
|
try { return (String) m.invoke(living); } catch(Exception e) { } return "game.neutral.hurt";
|
|
}
|
|
|
|
public static float getSoundVolume(EntityLivingBase living) {
|
|
Method m = ReflectionHelper.findMethod(EntityLivingBase.class, living, new String[] {"func_70599_aP", "getSoundVolume"});
|
|
try { return (float) m.invoke(living); } catch(Exception e) { } return 1F;
|
|
}
|
|
|
|
public static float getSoundPitch(EntityLivingBase living) {
|
|
Method m = ReflectionHelper.findMethod(EntityLivingBase.class, living, new String[] {"func_70647_i", "getSoundPitch"});
|
|
try { return (float) m.invoke(living); } catch(Exception e) { } return 1F;
|
|
}
|
|
|
|
@Deprecated public static void damageEntity(EntityLivingBase living, DamageSource source, float amount) {
|
|
if(!living.isEntityInvulnerable()) {
|
|
amount = ForgeHooks.onLivingHurt(living, source, amount);
|
|
if(amount <= 0)
|
|
return;
|
|
amount = applyArmorCalculations(living, source, amount); //#
|
|
amount = applyPotionDamageCalculations(living, source, amount); //#
|
|
float f1 = amount;
|
|
amount = Math.max(amount - living.getAbsorptionAmount(), 0.0F);
|
|
living.setAbsorptionAmount(living.getAbsorptionAmount() - (f1 - amount));
|
|
|
|
if(amount != 0.0F) {
|
|
float f2 = living.getHealth();
|
|
living.setHealth(f2 - amount);
|
|
living.func_110142_aN().func_94547_a(source, f2, amount);
|
|
living.setAbsorptionAmount(living.getAbsorptionAmount() - amount);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Deprecated public static float applyArmorCalculations(EntityLivingBase living, DamageSource source, float amount) {
|
|
if(!source.isUnblockable()) {
|
|
int i = 25 - living.getTotalArmorValue();
|
|
float armor = amount * (float) i;
|
|
//living.damageArmor(amount); //unused
|
|
amount = armor / 25.0F;
|
|
}
|
|
|
|
return amount;
|
|
}
|
|
|
|
public static float applyPotionDamageCalculations(EntityLivingBase living, DamageSource source, float amount) {
|
|
if(source.isDamageAbsolute()) {
|
|
return amount;
|
|
} else {
|
|
|
|
int resistance;
|
|
int j;
|
|
float f1;
|
|
|
|
if(living.isPotionActive(Potion.resistance) && source != DamageSource.outOfWorld) {
|
|
resistance = (living.getActivePotionEffect(Potion.resistance).getAmplifier() + 1) * 5;
|
|
j = 25 - resistance;
|
|
f1 = amount * (float) j;
|
|
amount = f1 / 25.0F;
|
|
}
|
|
|
|
if(amount <= 0.0F) {
|
|
return 0.0F;
|
|
} else {
|
|
|
|
resistance = EnchantmentHelper.getEnchantmentModifierDamage(living.getLastActiveItems(), source);
|
|
|
|
if(resistance > 20) {
|
|
resistance = 20;
|
|
}
|
|
|
|
if(resistance > 0 && resistance <= 20) {
|
|
j = 25 - resistance;
|
|
f1 = amount * (float) j;
|
|
amount = f1 / 25.0F;
|
|
}
|
|
|
|
return amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void setBeenAttacked(EntityLivingBase living) {
|
|
living.velocityChanged = living.getRNG().nextDouble() >= living.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).getAttributeValue();
|
|
}
|
|
|
|
public static MovingObjectPosition getMouseOver(EntityPlayer attacker, double reach) {
|
|
|
|
World world = attacker.worldObj;
|
|
MovingObjectPosition objectMouseOver = null;
|
|
Entity pointedEntity = null;
|
|
|
|
objectMouseOver = rayTrace(attacker, reach, 1F);
|
|
|
|
Vec3 pos = getPosition(attacker);
|
|
Vec3 look = attacker.getLook(1F);
|
|
Vec3 end = pos.addVector(look.xCoord * reach, look.yCoord * reach, look.zCoord * reach);
|
|
Vec3 hitvec = null;
|
|
float grace = 1.0F;
|
|
List list = world.getEntitiesWithinAABBExcludingEntity(attacker, attacker.boundingBox.addCoord(look.xCoord * reach, look.yCoord * reach, look.zCoord * reach).expand(grace, grace, grace));
|
|
|
|
double closest = reach;
|
|
|
|
for(int i = 0; i < list.size(); ++i) {
|
|
Entity entity = (Entity) list.get(i);
|
|
|
|
if(entity.canBeCollidedWith()) {
|
|
|
|
float borderSize = entity.getCollisionBorderSize();
|
|
AxisAlignedBB axisalignedbb = entity.boundingBox.expand(borderSize, borderSize, borderSize);
|
|
MovingObjectPosition movingobjectposition = axisalignedbb.calculateIntercept(pos, end);
|
|
|
|
if(axisalignedbb.isVecInside(pos)) {
|
|
if(0.0D <= closest) {
|
|
pointedEntity = entity;
|
|
hitvec = movingobjectposition == null ? pos : movingobjectposition.hitVec;
|
|
closest = 0.0D;
|
|
}
|
|
|
|
} else if(movingobjectposition != null) {
|
|
double dist = pos.distanceTo(movingobjectposition.hitVec);
|
|
|
|
if(dist < closest || closest == 0.0D) {
|
|
if(entity == attacker.ridingEntity && !entity.canRiderInteract()) {
|
|
if(closest == 0.0D) {
|
|
pointedEntity = entity;
|
|
hitvec = movingobjectposition.hitVec;
|
|
}
|
|
} else {
|
|
pointedEntity = entity;
|
|
hitvec = movingobjectposition.hitVec;
|
|
closest = dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pointedEntity != null && (closest < reach || objectMouseOver == null)) {
|
|
objectMouseOver = new MovingObjectPosition(pointedEntity, hitvec);
|
|
}
|
|
|
|
return objectMouseOver;
|
|
}
|
|
|
|
public static MovingObjectPosition rayTrace(EntityPlayer player, double dist, float interp) {
|
|
Vec3 pos = getPosition(player);
|
|
Vec3 look = player.getLook(interp);
|
|
Vec3 end = pos.addVector(look.xCoord * dist, look.yCoord * dist, look.zCoord * dist);
|
|
return player.worldObj.func_147447_a(pos, end, false, false, true);
|
|
}
|
|
|
|
public static Vec3 getPosition(EntityPlayer player) {
|
|
boolean client = player.yOffset != 0; // shitty hack to account for the weird offset rules i couldn't really work around otherwise
|
|
return Vec3.createVectorHelper(player.posX, player.posY + (client ? 0 : player.getEyeHeight()), player.posZ);
|
|
}
|
|
}
|