diff --git a/src/main/java/com/hbm/entity/missile/EntityMissileCustom.java b/src/main/java/com/hbm/entity/missile/EntityMissileCustom.java index 7429e0b8e..3b171440f 100644 --- a/src/main/java/com/hbm/entity/missile/EntityMissileCustom.java +++ b/src/main/java/com/hbm/entity/missile/EntityMissileCustom.java @@ -30,8 +30,8 @@ import net.minecraft.world.World; public class EntityMissileCustom extends EntityMissileBaseNT implements IChunkLoader { - protected float fuel; - protected float consumption; + public float fuel; + public float consumption; public EntityMissileCustom(World world) { super(world); @@ -81,6 +81,12 @@ public class EntityMissileCustom extends EntityMissileBaseNT implements IChunkLo @Override public void onUpdate() { + + ItemCustomMissilePart part = (ItemCustomMissilePart) Item.getItemById(this.dataWatcher.getWatchableObjectInt(9)); + WarheadType type = (WarheadType) part.attributes[0]; + if(type != null && type.updateCustom != null) { + type.updateCustom.accept(this); + } if(!worldObj.isRemote) { if(this.hasPropulsion()) this.fuel -= this.consumption; @@ -152,6 +158,11 @@ public class EntityMissileCustom extends EntityMissileBaseNT implements IChunkLo WarheadType type = (WarheadType) part.attributes[0]; float strength = (Float) part.attributes[1]; + + if(type.impactCustom != null) { + type.impactCustom.accept(this); + return; + } switch(type) { case HE: diff --git a/src/main/java/com/hbm/items/weapon/ItemCustomMissilePart.java b/src/main/java/com/hbm/items/weapon/ItemCustomMissilePart.java index 7c660a189..26c459982 100644 --- a/src/main/java/com/hbm/items/weapon/ItemCustomMissilePart.java +++ b/src/main/java/com/hbm/items/weapon/ItemCustomMissilePart.java @@ -2,7 +2,9 @@ package com.hbm.items.weapon; import java.util.HashMap; import java.util.List; +import java.util.function.Consumer; +import com.hbm.entity.missile.EntityMissileCustom; import com.hbm.items.special.ItemLootCrate; import com.hbm.lib.RefStrings; import com.hbm.main.MainRegistry; @@ -86,7 +88,17 @@ public class ItemCustomMissilePart extends Item { SCHRAB, TAINT, CLOUD, - TURBINE + TURBINE, + + //shit solution but it works. this allows traits to be attached to these empty dummy types, allowing for custom warheads + CUSTOM0, CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5, CUSTOM6, CUSTOM7, CUSTOM8, CUSTOM9; + + /** Overrides that type's impact effect. Only runs serverside */ + public Consumer impactCustom = null; + /** Runs at the beginning of the missile's update cycle, both client and serverside. */ + public Consumer updateCustom = null; + /** Override for the warhead's name in the missile description */ + public String labelCustom = null; } public enum FuelType { @@ -246,6 +258,8 @@ public class ItemCustomMissilePart extends Item { public String getWarhead(WarheadType type) { + if(type.labelCustom != null) return type.labelCustom; + switch(type) { case HE: return EnumChatFormatting.YELLOW + "HE"; diff --git a/src/main/java/com/hbm/main/MainRegistry.java b/src/main/java/com/hbm/main/MainRegistry.java index b32dace00..1ffb32eac 100644 --- a/src/main/java/com/hbm/main/MainRegistry.java +++ b/src/main/java/com/hbm/main/MainRegistry.java @@ -864,6 +864,7 @@ public class MainRegistry { TileEntityNukeCustom.registerBombItems(); ArmorUtil.register(); HazmatRegistry.registerHazmats(); + DamageResistanceHandler.init(); FluidContainerRegistry.register(); BlockToolConversion.registerRecipes(); AchievementHandler.register(); diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineWoodBurner.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineWoodBurner.java index c29468236..3a1ebe90b 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineWoodBurner.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineWoodBurner.java @@ -97,7 +97,7 @@ public class TileEntityMachineWoodBurner extends TileEntityMachineBase implement this.maxBurnTime = this.burnTime = burn; ItemStack container = slots[0].getItem().getContainerItem(slots[0]); this.decrStackSize(0, 1); - if(slots[0] == null) slots[0] = container.copy(); + if(slots[0] == null && container != null) slots[0] = container.copy(); this.markChanged(); } } diff --git a/src/main/java/com/hbm/util/CompatExternal.java b/src/main/java/com/hbm/util/CompatExternal.java index 088190002..2bb276490 100644 --- a/src/main/java/com/hbm/util/CompatExternal.java +++ b/src/main/java/com/hbm/util/CompatExternal.java @@ -1,11 +1,21 @@ package com.hbm.util; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Consumer; + import api.hbm.energymk2.IEnergyHandlerMK2; import api.hbm.energymk2.IEnergyReceiverMK2; import api.hbm.fluid.IFluidUser; import com.hbm.blocks.BlockDummyable; +import com.hbm.entity.missile.EntityMissileCustom; +import com.hbm.explosion.ExplosionNukeSmall; import com.hbm.inventory.fluid.FluidType; import com.hbm.inventory.fluid.tank.FluidTank; +import com.hbm.items.weapon.ItemCustomMissilePart.WarheadType; import com.hbm.tileentity.machine.TileEntityDummy; import com.hbm.tileentity.turret.TileEntityTurretSentry; import net.minecraft.block.Block; @@ -14,6 +24,7 @@ import net.minecraft.entity.passive.EntityChicken; import net.minecraft.entity.passive.EntityCow; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; import java.util.ArrayList; @@ -175,9 +186,13 @@ public class CompatExternal { * class on the side of whoever is adding compat, allowing the compat class to be used entirely with reflection. */ public static void registerTurretTargetingCondition(Class clazz, BiFunction bi) { - turretTargetBlacklist.add(clazz); + turretTargetCondition.put(clazz, bi); } + public static void setWarheadLabel(WarheadType type, String label) { type.labelCustom = label; } + public static void setWarheadImpact(WarheadType type, Consumer impact) { type.impactCustom = impact; } + public static void setWarheadUpdate(WarheadType type, Consumer update) { type.updateCustom = update; } + public static void compatExamples() { // Makes all cows be targeted by turrets if player mode is active in addition to the existing rules. Applies to all entities that inherit EntityCow. CompatExternal.registerTurretTargetSimple(EntityCow.class, 0); @@ -189,5 +204,10 @@ public class CompatExternal { if(turret instanceof TileEntityTurretSentry) return -1; return 0; }); + //configures CUSTOM0 to have a custom label and impact effect + CompatExternal.setWarheadLabel(WarheadType.CUSTOM0, EnumChatFormatting.YELLOW + "Micro Nuke"); + CompatExternal.setWarheadImpact(WarheadType.CUSTOM0, (missile) -> { + ExplosionNukeSmall.explode(missile.worldObj, missile.posX, missile.posY + 0.5, missile.posZ, ExplosionNukeSmall.PARAMS_MEDIUM); + }); } } diff --git a/src/main/java/com/hbm/util/CrucibleUtil.java b/src/main/java/com/hbm/util/CrucibleUtil.java index d5cfd62aa..222abab88 100644 --- a/src/main/java/com/hbm/util/CrucibleUtil.java +++ b/src/main/java/com/hbm/util/CrucibleUtil.java @@ -64,6 +64,7 @@ public class CrucibleUtil { } for(MaterialStack stack : stacks) { + if(stack.material == null) continue; int amountToPour = Math.min(stack.amount, quanta); MaterialStack toPour = new MaterialStack(stack.material, amountToPour); diff --git a/src/main/java/com/hbm/util/DamageResistanceHandler.java b/src/main/java/com/hbm/util/DamageResistanceHandler.java new file mode 100644 index 000000000..2c66e712c --- /dev/null +++ b/src/main/java/com/hbm/util/DamageResistanceHandler.java @@ -0,0 +1,105 @@ +package com.hbm.util; + +import java.util.HashMap; + +import com.hbm.util.Tuple.Quartet; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.MathHelper; + +/** + * Basic handling/registry class for our custom resistance stats. + * Handles resistances for individual armor pieces, full sets as well as entity classes for innate damage resistance + * + * @author hbm + */ +public class DamageResistanceHandler { + + public static HashMap itemStats = new HashMap(); + public static HashMap, ResistanceStats> setStats = new HashMap(); + public static HashMap, ResistanceStats> entityStats = new HashMap(); + + public static void init() { + + } + + public static float calculateDamage(EntityLivingBase entity, DamageSource damage, float amount, float pierceDT, float pierce) { + if(damage.isDamageAbsolute() || damage.isUnblockable()) return amount; + + String key = damage.damageType; + float dt = 0; + float dr = 0; + + /// SET HANDLING /// + Quartet wornSet = new Quartet( + entity.getEquipmentInSlot(1) != null ? entity.getEquipmentInSlot(1).getItem() : null, + entity.getEquipmentInSlot(2) != null ? entity.getEquipmentInSlot(2).getItem() : null, + entity.getEquipmentInSlot(3) != null ? entity.getEquipmentInSlot(3).getItem() : null, + entity.getEquipmentInSlot(4) != null ? entity.getEquipmentInSlot(4).getItem() : null + ); + + ResistanceStats setResistance = setStats.get(wornSet); + if(setResistance != null) { + Resistance res = setResistance.resistances.get(key); + if(res != null) { + dt += res.threshold; + dr += res.resistance; + } + } + + /// ARMOR /// + for(int i = 1; i <= 4; i++) { + ItemStack armor = entity.getEquipmentInSlot(i); + if(armor == null) continue; + ResistanceStats stats = itemStats.get(armor.getItem()); + if(stats == null) continue; + Resistance res = stats.resistances.get(key); + if(res == null) continue; + dt += res.threshold; + dr += res.resistance; + } + + /// ENTITY CLASS HANDLING /// + ResistanceStats innateResistance = entityStats.get(entity.getClass()); + if(innateResistance != null) { + Resistance res = innateResistance.resistances.get(key); + if(res != null) { + dt += res.threshold; + dr += res.resistance; + } + } + + /// MATH /// + dt = Math.max(0F, dt - pierceDT); + if(dt <= amount) return 0F; + amount -= dt; + dr *= MathHelper.clamp_float(1F - pierce, 0F, 1F); + + return amount *= (1F - dr); + } + + public static class ResistanceStats { + + public HashMap resistances = new HashMap(); + + public ResistanceStats add(String type, float threshold, float resistance) { + resistances.put(type, new Resistance(threshold, resistance)); + return this; + } + } + + public static class Resistance { + + public float threshold; + public float resistance; + + public Resistance(float threshold, float resistance) { + this.threshold = threshold; + this.resistance = resistance; + } + } +} diff --git a/src/main/java/com/hbm/util/EntityDamageUtil.java b/src/main/java/com/hbm/util/EntityDamageUtil.java index d91bf230c..27ec42b6e 100644 --- a/src/main/java/com/hbm/util/EntityDamageUtil.java +++ b/src/main/java/com/hbm/util/EntityDamageUtil.java @@ -21,10 +21,10 @@ import net.minecraftforge.common.ForgeHooks; public class EntityDamageUtil { /** - * Attacks the given entity twice, based on a piecring percentage. The second hit sets the damage source to bypass armor. + * Attacks the given entity twice, based on a piercing percentage. The second hit sets the damage source to bypass armor. * The damage source is modified, so you can't reuse damage source instances. */ - public static boolean attackEntityFromArmorPiercing(Entity victim, DamageSource src, float damage, float piercing) { + @Deprecated public static boolean attackEntityFromArmorPiercing(Entity victim, DamageSource src, float damage, float piercing) { if(src.isUnblockable() || piercing == 0) return victim.attackEntityFrom(src, damage); @@ -58,14 +58,14 @@ public class EntityDamageUtil { } } - public static float getDamageAfterTax(EntityLivingBase living, DamageSource source, float amount) { + @Deprecated public static float getDamageAfterTax(EntityLivingBase living, DamageSource source, float amount) { amount = ForgeHooks.onLivingHurt(living, source, amount); if(amount <= 0) return 0; amount = applyArmorCalculations(living, source, amount); return amount; } - public static boolean attackArmorPiercing(EntityLivingBase living, DamageSource sourceDamageCalc, DamageSource sourceArmorPiercing, float amount, float piercing) { + @Deprecated public static boolean attackArmorPiercing(EntityLivingBase living, DamageSource sourceDamageCalc, DamageSource sourceArmorPiercing, float amount, float piercing) { if(piercing <= 0) return living.attackEntityFrom(sourceDamageCalc, amount); //damage intended to pass the armor float afterTax = getDamageAfterTax(living, sourceDamageCalc, amount); @@ -73,11 +73,128 @@ public class EntityDamageUtil { float reduced = Math.max(amount - afterTax, 0F); //damage that would pass + damage tthat wouldn't pass * AP percentage return attackEntityFromIgnoreIFrame(living, sourceArmorPiercing, Math.max(afterTax + (reduced * piercing), 0F)); + } + + public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) { + if(ForgeHooks.onLivingAttack(living, source, amount) && allowSpecialCancel) return false; + if(living.isEntityInvulnerable()) return false; + if(living.worldObj.isRemote) 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); //TODO: override + living.lastDamage = amount; + didAttackRegister = false; + } else { + living.lastDamage = amount; + living.prevHealth = living.getHealth(); + living.hurtResistantTime = living.maxHurtResistantTime; + damageEntityNT(living, source, amount); //TODO: override + 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) living.knockBack(entity, amount, deltaX * knockbackMultiplier, 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 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()) { + int i = 25 - living.getTotalArmorValue(); + float armor = amount * (float) i; + damageArmorNT(living, amount); + amount = armor / 25.0F; + + //TODO: special handling depending on armor stats + } + + return amount; + } + + public static void damageArmorNT(EntityLivingBase living, float amount) { } /** Currently just a copy of the vanilla damage code */ - public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount) { + @Deprecated public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount) { if(ForgeHooks.onLivingAttack(living, source, amount)) return false; @@ -204,7 +321,7 @@ public class EntityDamageUtil { try { return (float) m.invoke(living); } catch(Exception e) { } return 1F; } - public static void damageEntity(EntityLivingBase living, DamageSource source, float amount) { + @Deprecated public static void damageEntity(EntityLivingBase living, DamageSource source, float amount) { if(!living.isEntityInvulnerable()) { amount = ForgeHooks.onLivingHurt(living, source, amount); if(amount <= 0) @@ -224,11 +341,11 @@ public class EntityDamageUtil { } } - public static float applyArmorCalculations(EntityLivingBase living, DamageSource source, float 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(p_70655_2_); //unused + //living.damageArmor(amount); //unused amount = armor / 25.0F; } diff --git a/src/main/resources/assets/hbm/my_hecking_realism.png b/src/main/resources/assets/hbm/my_hecking_realism.png new file mode 100644 index 000000000..dab8b86bc Binary files /dev/null and b/src/main/resources/assets/hbm/my_hecking_realism.png differ