package com.flansmod.common.guns.raytracing;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
import com.flansmod.client.debug.EntityDebugAABB;
import com.flansmod.client.debug.EntityDebugDot;
import com.flansmod.common.FlansMod;
import com.flansmod.common.PlayerData;
import com.flansmod.common.PlayerHandler;
import com.flansmod.common.RotatedAxes;
import com.flansmod.common.guns.BulletType;
import com.flansmod.common.guns.EntityBullet;
import com.flansmod.common.guns.GunType;
import com.flansmod.common.guns.ItemGun;
import com.flansmod.common.guns.raytracing.FlansModRaytracer.PlayerBulletHit;
import com.flansmod.common.teams.TeamsManager;
import com.flansmod.common.types.InfoType;
import com.flansmod.common.vector.Vector3f;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class PlayerHitbox
{
/** */
public EntityPlayer player;
/** The angles of this box */
public RotatedAxes axes;
/** The origin of rotation for this box */
public Vector3f rP;
/** The lower left corner of this box */
public Vector3f o;
/** The dimensions of this box */
public Vector3f d;
/** The type of hitbox */
public EnumHitboxType type;
public PlayerHitbox(EntityPlayer player, RotatedAxes axes, Vector3f rotationPoint, Vector3f origin, Vector3f dimensions, EnumHitboxType type)
{
this.player = player;
this.axes = axes;
this.o = origin;
this.d = dimensions;
this.type = type;
this.rP = rotationPoint;
}
@SideOnly(Side.CLIENT)
public void renderHitbox(World world, Vector3f pos)
{
//Vector3f boxOrigin = new Vector3f(pos.x + rP.x, pos.y + rP.y, pos.z + rP.z);
//world.spawnEntityInWorld(new EntityDebugAABB(world, boxOrigin, d, 2, 1F, 1F, 0F, axes.getYaw(), axes.getPitch(), axes.getRoll(), o));
if(type != EnumHitboxType.RIGHTARM)
return;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
for(int k = 0; k < 3; k++)
{
Vector3f point = new Vector3f(o.x + d.x * i / 2, o.y + d.y * j / 2, o.z + d.z * k / 2);
point = axes.findLocalVectorGlobally(point);
world.spawnEntityInWorld(new EntityDebugDot(world, new Vector3f(pos.x + rP.x + point.x, pos.y + rP.y + point.y, pos.z + rP.z + point.z), 1, 0F, 1F, 0F));
}
}
public PlayerBulletHit raytrace(Vector3f origin, Vector3f motion)
{
//Move to local coords for this hitbox, but don't modify the original "origin" vector
origin = Vector3f.sub(origin, rP, null);
origin = axes.findGlobalVectorLocally(origin);
motion = axes.findGlobalVectorLocally(motion);
//We now have an AABB starting at o and with dimensions d and our ray in the same coordinate system
//We are looking for a point at which the ray enters the box, so we need only consider faces that the ray can see. Partition the space into 3 areas in each axis
//X - axis and faces x = o.x and x = o.x + d.x
if(motion.x != 0F)
{
if(origin.x < o.x) //Check face x = o.x
{
float intersectTime = (o.x - origin.x) / motion.x;
float intersectY = origin.y + motion.y * intersectTime;
float intersectZ = origin.z + motion.z * intersectTime;
if(intersectY >= o.y && intersectY <= o.y + d.y && intersectZ >= o.z && intersectZ <= o.z + d.z)
return new PlayerBulletHit(this, intersectTime);
}
else if(origin.x > o.x + d.x) //Check face x = o.x + d.x
{
float intersectTime = (o.x + d.x - origin.x) / motion.x;
float intersectY = origin.y + motion.y * intersectTime;
float intersectZ = origin.z + motion.z * intersectTime;
if(intersectY >= o.y && intersectY <= o.y + d.y && intersectZ >= o.z && intersectZ <= o.z + d.z)
return new PlayerBulletHit(this, intersectTime);
}
}
//Z - axis and faces z = o.z and z = o.z + d.z
if(motion.z != 0F)
{
if(origin.z < o.z) //Check face z = o.z
{
float intersectTime = (o.z - origin.z) / motion.z;
float intersectX = origin.x + motion.x * intersectTime;
float intersectY = origin.y + motion.y * intersectTime;
if(intersectX >= o.x && intersectX <= o.x + d.x && intersectY >= o.y && intersectY <= o.y + d.y)
return new PlayerBulletHit(this, intersectTime);
}
else if(origin.z > o.z + d.z) //Check face z = o.z + d.z
{
float intersectTime = (o.z + d.z - origin.z) / motion.z;
float intersectX = origin.x + motion.x * intersectTime;
float intersectY = origin.y + motion.y * intersectTime;
if(intersectX >= o.x && intersectX <= o.x + d.x && intersectY >= o.y && intersectY <= o.y + d.y)
return new PlayerBulletHit(this, intersectTime);
}
}
//Y - axis and faces y = o.y and y = o.y + d.y
if(motion.y != 0F)
{
if(origin.y < o.y) //Check face y = o.y
{
float intersectTime = (o.y - origin.y) / motion.y;
float intersectX = origin.x + motion.x * intersectTime;
float intersectZ = origin.z + motion.z * intersectTime;
if(intersectX >= o.x && intersectX <= o.x + d.x && intersectZ >= o.z && intersectZ <= o.z + d.z)
return new PlayerBulletHit(this, intersectTime);
}
else if(origin.y > o.y + d.y) //Check face x = o.x + d.x
{
float intersectTime = (o.y + d.y - origin.y) / motion.y;
float intersectX = origin.x + motion.x * intersectTime;
float intersectZ = origin.z + motion.z * intersectTime;
if(intersectX >= o.x && intersectX <= o.x + d.x && intersectZ >= o.z && intersectZ <= o.z + d.z)
return new PlayerBulletHit(this, intersectTime);
}
}
return null;
}
public float hitByBullet(DamageSource source, Entity damageOwner, InfoType firedFrom, BulletType bulletType, float damage, float penetratingPower)
{
if(bulletType.setEntitiesOnFire)
player.setFire(20);
for(PotionEffect effect : bulletType.hitEffects)
{
player.addPotionEffect(new PotionEffect(effect));
}
float damageModifier = bulletType.penetratingPower < 0.1F ? penetratingPower / bulletType.penetratingPower : 1;
switch(type)
{
case BODY : break;
case HEAD : damageModifier *= 2F; break;
case LEFTARM : damageModifier *= 0.6F; break;
case RIGHTARM : damageModifier *= 0.6F; break;
case LEFTITEM : break;
case RIGHTITEM : break;
default : break;
}
switch(type)
{
case BODY : case HEAD : case LEFTARM : case RIGHTARM :
{
//Calculate the hit damage
float hitDamage = damage * bulletType.damageVsLiving * damageModifier;
//Create a damage source object
DamageSource damagesource = damageOwner == null ? DamageSource.generic
: EntityBullet.GetBulletDamage(firedFrom, bulletType, damageOwner, type == EnumHitboxType.HEAD);
//When the damage is 0 (such as with Nerf guns) the entityHurt Forge hook is not called, so this hacky thing is here
if(!player.worldObj.isRemote && hitDamage == 0 && TeamsManager.getInstance().currentRound != null)
TeamsManager.getInstance().currentRound.gametype.playerAttacked((EntityPlayerMP)player, damagesource);
//Attack the entity!
if(player.attackEntityFrom(damagesource, hitDamage))
{
//If the attack was allowed, we should remove their immortality cooldown so we can shoot them again. Without this, any rapid fire gun become useless
player.arrowHitTimer++;
player.hurtResistantTime = player.maxHurtResistantTime / 2;
//Yuck.
//PacketDispatcher.sendPacketToAllAround(posX, posY, posZ, 50, dimension, PacketPlaySound.buildSoundPacket(posX, posY, posZ, type.hitSound, true));
}
return penetratingPower - 1;
}
case RIGHTITEM :
{
ItemStack currentStack = player.getCurrentEquippedItem();
if(currentStack != null && currentStack.getItem() instanceof ItemGun)
{
GunType gunType = ((ItemGun)currentStack.getItem()).GetType();
//TODO : Shield damage
return penetratingPower - gunType.shieldDamageAbsorption;
}
else return penetratingPower;
}
case LEFTITEM :
{
PlayerData data = PlayerHandler.getPlayerData(player);
if(data.offHandGunSlot != 0)
{
ItemStack leftHandStack = null;
if(player.worldObj.isRemote && !FlansMod.proxy.isThePlayer(player))
leftHandStack = data.offHandGunStack;
else leftHandStack = player.inventory.getStackInSlot(data.offHandGunSlot - 1);
if(leftHandStack != null && leftHandStack.getItem() instanceof ItemGun)
{
GunType leftGunType = ((ItemGun)leftHandStack.getItem()).GetType();
//TODO : Shield damage
return penetratingPower - leftGunType.shieldDamageAbsorption;
}
}
}
default : return penetratingPower;
}
}
}