package com.mrcrayfish.skateboarding.entity;
import com.mrcrayfish.skateboarding.MrCrayfishSkateboardingMod;
import com.mrcrayfish.skateboarding.api.trick.Flip;
import com.mrcrayfish.skateboarding.api.trick.Grind;
import com.mrcrayfish.skateboarding.api.trick.Trick;
import com.mrcrayfish.skateboarding.block.BlockSlope;
import com.mrcrayfish.skateboarding.block.attributes.Angled;
import com.mrcrayfish.skateboarding.network.PacketHandler;
import com.mrcrayfish.skateboarding.network.message.MessageStack;
import com.mrcrayfish.skateboarding.network.message.MessageUpdatePos;
import com.mrcrayfish.skateboarding.util.ComboBuilder;
import com.mrcrayfish.skateboarding.util.GrindHelper;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class EntitySkateboard extends Entity
{
public ComboBuilder combo = new ComboBuilder();
public double currentSpeed = 0.0;
public double maxSpeed = 8.0;
private boolean pushed = false;
private boolean jumping = false;
private int jumpingTimer = 0;
private int inTrickTimer = 0;
private Trick currentTrick = null;
private boolean allowJumpOnce = false;
private boolean grinding = false;
private boolean goofy = false;
private boolean switch_ = false;
private boolean flipped = false;
private boolean onAngledBlock = false;
private IBlockState angledBlockState;
private Angled angledBlock;
public float angleOnJump;
private float angleOnTrick;
private int rotation;
@SideOnly(Side.CLIENT)
private double velocityX;
@SideOnly(Side.CLIENT)
private double velocityY;
@SideOnly(Side.CLIENT)
private double velocityZ;
public double boardYaw;
public double prevBoardYaw;
public double boardRotationX;
public double boardRotationY;
public double boardRotationZ;
public double prevBoardRotationX;
public double prevBoardRotationY;
public double prevBoardRotationZ;
public boolean needsCameraUpdate;
public boolean canCameraIncrement;
public float cameraIncrement;
public float cameraYaw;
public EntitySkateboard(World worldIn)
{
super(worldIn);
this.setSize(0.5F, 0.25F);
this.stepHeight = 0.3F;
}
public EntitySkateboard(World worldIn, double x, double y, double z)
{
this(worldIn);
this.setPosition(x, y, z);
}
@Override
protected boolean canTriggerWalking()
{
return false;
}
@Override
@SideOnly(Side.CLIENT)
public boolean shouldRiderSit()
{
return true;
}
@Override
protected void entityInit()
{
}
@Override
public double getMountedYOffset()
{
return 0.5F + (0.04F * rand.nextDouble()) * (currentSpeed / maxSpeed);
}
@Override
public boolean canBePushed()
{
return false;
}
@Override
public boolean canBeCollidedWith()
{
return true;
}
/*@Override
@SideOnly(Side.CLIENT)
public void func_180426_a(double p_180426_1_, double p_180426_3_, double p_180426_5_, float p_180426_7_, float p_180426_8_, int p_180426_9_, boolean p_180426_10_)
{
if (this.riddenByEntity != null)
{
this.prevPosX = this.posX = p_180426_1_;
this.prevPosY = this.posY = p_180426_3_;
this.prevPosZ = this.posZ = p_180426_5_;
this.rotationYaw = p_180426_7_;
this.rotationPitch = p_180426_8_;
this.setPosition(p_180426_1_, p_180426_3_, p_180426_5_);
this.motionX = this.velocityX = 0.0D;
this.motionY = this.velocityY = 0.0D;
this.motionZ = this.velocityZ = 0.0D;
}
else
{
this.motionX = this.velocityX;
this.motionY = this.velocityY;
this.motionZ = this.velocityZ;
}
}*/
/*@SideOnly(Side.CLIENT)
public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport)
{
this.prevPosX = this.posX = x;
this.prevPosY = this.posY = y;
this.prevPosZ = this.posX = z;
this.rotationYaw = yaw;
this.rotationPitch = pitch;
this.motionX = this.velocityX;
this.motionY = this.velocityY;
this.motionZ = this.velocityZ;
}
@Override
@SideOnly(Side.CLIENT)
public void setVelocity(double x, double y, double z)
{
this.velocityX = this.motionX = x;
this.velocityY = this.motionY = y;
this.velocityZ = this.motionZ = z;
}*/
@Override
public void onUpdate()
{
super.onUpdate();
prevRotationYaw = rotationYaw;
if(worldObj.isRemote)
{
combo.update(this);
prevBoardYaw = boardYaw;
prevBoardRotationX = boardRotationX;
prevBoardRotationY = boardRotationY;
prevBoardRotationZ = boardRotationZ;
}
/* Will only execute code if player is riding skateboard */
Entity entity = getControllingPassenger();
if (entity instanceof EntityLivingBase)
{
EntityLivingBase entityLiving = (EntityLivingBase) entity;
/* Handles pushing */
if (entityLiving.moveForward > 0 && !pushed && !grinding)
{
if (currentSpeed <= maxSpeed - 1.0)
{
currentSpeed += 1.0D;
}
pushed = true;
}
else if (entityLiving.moveForward == 0.0)
{
pushed = false;
}
/* If skateboard is not jumping, allow turning. When player jumps
* from grinding, give exception to jump off in a direction using
* allowOnce. */
if ((!jumping || allowJumpOnce) && !needsCameraUpdate)
{
float f = entity.rotationYaw;
/* If grinding, set direction to direction of grinding. */
if (grinding)
{
//TODO:: If easy mode?
//f = EnumFacing.fromAngle(this.angleOnJump).rotateY().getHorizontalIndex() * 90F;
}
this.motionX = -Math.sin((double) (f * (float) Math.PI / 180.0F)) * currentSpeed / 16D;
this.motionZ = Math.cos((double) (f * (float) Math.PI / 180.0F)) * currentSpeed / 16D;
this.rotationYaw = entity.rotationYaw - 90F;
allowJumpOnce = false;
}
if(needsCameraUpdate && worldObj.isRemote)
{
canCameraIncrement = true;
cameraYaw -= cameraIncrement;
if(Math.floor(cameraYaw) == 0F)
{
needsCameraUpdate = false;
}
}
}
else
{
/* If no player riding, make the board stop */
this.currentSpeed = 0;
this.motionX = 0;
this.motionZ = 0;
}
/* If collided horizontally, slow current speed by 75% */
if (isCollidedHorizontally)
{
this.currentSpeed *= 0.75D;
}
/* Gravity? */
this.motionY -= 0.08D;
/* If grinding, make position of skateboard go to center of block.
if (grinding)
{
double[] offsets = ((Grind) getCurrentTrick()).offsetBoardPosition(this);
EnumFacing face = EnumFacing.fromAngle(this.angleOnJump).rotateY();
if (face == EnumFacing.NORTH | face == EnumFacing.SOUTH)
{
this.setPosition(Math.floor(this.posX) + 0.5 + offsets[0], Math.floor(this.posY) + offsets[1], this.posZ + offsets[2]);
}
if (face == EnumFacing.EAST | face == EnumFacing.WEST)
{
this.setPosition(this.posX + offsets[0], Math.floor(this.posY) + offsets[1], Math.floor(this.posZ) + 0.5 + offsets[2]);
}
}*/
if (jumping)
{
if (entity instanceof EntityLivingBase)
{
EntityLivingBase entityLiving = (EntityLivingBase) entity;
this.rotationYaw = entity.rotationYaw - 90F;
}
//if (jumpingTimer < 10)
//motionY = 0.5D - (double) jumpingTimer * 0.03D;
if(worldObj.isRemote)
{
if (currentTrick != null)
{
inTrickTimer++;
currentTrick.updateBoard(this);
if (currentTrick instanceof Flip)
{
Flip flip = (Flip) currentTrick;
if (inTrickTimer > flip.performTime())
{
if (worldObj.isRemote)
{
boolean direction = angleOnJump < rotationYaw;
if((!isGoofy() && isSwitch_()) || (isGoofy() && !isSwitch_())) direction ^= true;
combo.addTrick(getCurrentTrick(), Math.abs(angleOnJump - rotationYaw), direction);
}
getCurrentTrick().onEnd(this);
resetTrick();
}
}
}
if (onGround && !grinding)
{
jumping = false;
jumpingTimer = 0;
if(currentTrick != null)
{
if (currentTrick instanceof Flip)
{
resetTrick();
PacketHandler.INSTANCE.sendToServer(new MessageStack(this.getEntityId()));
}
}
handleLanding();
}
jumpingTimer++;
}
}
this.moveEntity(this.motionX, this.motionY, this.motionZ);
if (grinding && worldObj.isRemote)
{
if (currentTrick instanceof Grind)
{
inTrickTimer++;
prevBoardYaw = boardYaw;
prevBoardRotationX = boardRotationX;
prevBoardRotationY = boardRotationY;
prevBoardRotationZ = boardRotationZ;
currentTrick.updateBoard(this);
Grind grind = (Grind) currentTrick;
if (!GrindHelper.canGrind(worldObj, this.posX, this.posY, this.posZ))
{
getCurrentTrick().onEnd(this);
resetTrick();
grinding = false;
onGround = false;
}
else
{
combo.addPoints(getCurrentTrick().points());
}
worldObj.spawnParticle(EnumParticleTypes.FIREWORKS_SPARK, posX, posY, posZ, 0, 0, 0, 0);
}
//TODO: If easy mode
//this.rotationYaw = (int) (angleOnJump + (rotationYaw - angleOnJump) + 45) / 90 * 90;
}
if (!grinding)
{
this.currentSpeed *= 0.99D;
}
//}
}
@Override
public EnumActionResult applyPlayerInteraction(EntityPlayer player, Vec3d vec, ItemStack stack, EnumHand hand)
{
if(player.isSneaking()) {
this.setDead();
} else {
player.startRiding(this, false);
prevRotationYaw = rotationYaw = player.rotationYaw - 90F;
}
return EnumActionResult.SUCCESS;
}
/*@Override
public void updateRidden()
{
if(getControllingPassenger() != null)
{
((EntityLivingBase) getControllingPassenger()).setRenderYawOffset(rotationYaw + (this.isGoofy() ? -90F : 90F));
}
}*/
@Override
public void updatePassenger(Entity passenger)
{
super.updatePassenger(passenger);
}
/*@Override
public void updateRiderPosition()
{
if (this.riddenByEntity != null)
{
this.riddenByEntity.setPosition(this.posX, this.posY + this.getMountedYOffset() + this.riddenByEntity.getYOffset() + (currentTrick != null && !grinding ? 0.25D : 0D), this.posZ);
if (this.riddenByEntity instanceof EntityLivingBase)
{
((EntityLivingBase) this.riddenByEntity).renderYawOffset = this.rotationYaw + (this.isGoofy() ? -90F : 90F);
}
}
}
@Override
public boolean interactFirst(EntityPlayer playerIn)
{
if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this.riddenByEntity != playerIn)
{
return true;
}
else
{
if (!this.worldObj.isRemote)
{
playerIn.mountEntity(this);
}
return true;
}
}*/
@Override
protected void readEntityFromNBT(NBTTagCompound tagCompund)
{
}
@Override
protected void writeEntityToNBT(NBTTagCompound tagCompound)
{
}
public void push()
{
this.currentSpeed += 1;
}
public void handleLanding()
{
if (worldObj.isRemote)
{
int difference = (int) (Math.abs(angleOnJump - rotationYaw) % 180);
if(currentSpeed > 4 && difference > 60 && difference < 120)
{
PacketHandler.INSTANCE.sendToServer(new MessageStack(this.getEntityId()));
}
else
{
int dir = angleOnJump < rotationYaw ? 1 : -1;
float fakie = (Math.abs(angleOnJump - rotationYaw) / 180) % 2;
if(fakie > 0.66 && fakie < 1.33)
{
this.rotationYaw += 180F * dir;
this.prevRotationYaw = this.rotationYaw;
this.setSwitch_(!isSwitch_());
this.setFlipped();
this.setCameraUpdate(180F * dir);
}
}
}
//print();
}
public void performStack()
{
Entity riding = getControllingPassenger();
if (!worldObj.isRemote && riding != null)
{
riding.attackEntityFrom(MrCrayfishSkateboardingMod.skateboardDamage, 2);
if (riding instanceof EntityLivingBase)
{
riding.dismountRidingEntity();
}
}
}
public void startTrick(Trick trick)
{
currentTrick = trick;
if (trick instanceof Flip)
{
Flip flip = (Flip) trick;
if(!isJumping())
{
resetTrick();
return;
}
onGround = false;
}
if (trick instanceof Grind)
{
if (GrindHelper.canGrind(worldObj, posX, posY, posZ))
{
handleLanding();
combo.addTrick(trick, 0, true);
jumping = false;
jumpingTimer = 0;
grinding = true;
onGround = false;
float newYaw = (float) Math.floor((rotationYaw + 45F) / 90F) * 90F;
turnToDirection(newYaw);
moveToDirectionCenter(newYaw);
}
else
{
currentTrick = null;
}
}
if(currentTrick != null)
{
currentTrick.onStart(this);
}
}
public void resetTrick()
{
if(currentTrick instanceof Flip)
{
prevBoardYaw = 0F;
prevBoardRotationX = 0F;
prevBoardRotationY = 0F;
prevBoardRotationZ = 0F;
}
currentTrick = null;
inTrickTimer = 0;
boardYaw = 0F;
boardRotationX = 0F;
boardRotationY = 0F;
boardRotationZ = 0F;
}
public void jump(double height)
{
if (grinding)
{
jumping = false;
jumpingTimer = 0;
grinding = false;
allowJumpOnce = true;
}
resetTrick();
jumping = true;
onGround = false;
angleOnJump = rotationYaw;
prevRotationYaw = rotationYaw;
motionY = Math.sqrt((height + 1) * 0.22);
}
public void turnToDirection(float newYaw)
{
Entity entity = getControllingPassenger();
float startYaw = entity.rotationYaw - 90F;
rotationYaw = newYaw;
prevRotationYaw = newYaw;
this.setCameraUpdate(newYaw - startYaw);
}
public void moveToDirectionCenter(float yaw)
{
EnumFacing facing = EnumFacing.fromAngle(yaw);
Axis axis = facing.getAxis();
switch(axis)
{
case X:
this.motionX = 0;
this.lastTickPosX = this.prevPosX = this.posX = Math.floor(posX) + 0.5;
PacketHandler.INSTANCE.sendToServer(new MessageUpdatePos(getEntityId(), Math.floor(posX) + 0.5, posY, posZ));
break;
case Z:
this.motionZ = 0;
this.lastTickPosZ = this.prevPosZ = this.posZ = Math.floor(posZ) + 0.5;
PacketHandler.INSTANCE.sendToServer(new MessageUpdatePos(getEntityId(), posX, posY, Math.floor(posZ) + 0.5));
break;
default:
break;
}
this.updateBoundingBox(posX, posY, posZ);
this.updatePassenger(getControllingPassenger());
}
public void updateBoundingBox(double x, double y, double z)
{
float f = this.width / 2.0F;
float f1 = this.height;
this.setEntityBoundingBox(new AxisAlignedBB(x - (double) f, y, z - (double)f, x + (double)f, y + (double)f1, z + (double)f));
}
public boolean isPushed()
{
return pushed;
}
public void setPushed(boolean pushed)
{
this.pushed = pushed;
}
public boolean isJumping()
{
return jumping;
}
public void setJumping(boolean jumping)
{
this.jumping = jumping;
}
public boolean isInTrick()
{
return currentTrick != null;
}
public Trick getCurrentTrick()
{
return currentTrick;
}
public void setCurrentTrick(Trick currentTrick)
{
this.currentTrick = currentTrick;
}
public boolean isGrinding()
{
return grinding;
}
public void setGrinding(boolean grinding)
{
this.grinding = grinding;
}
public boolean isGoofy()
{
return goofy;
}
public void setGoofy(boolean goofy)
{
this.goofy = goofy;
}
public boolean isSwitch_()
{
return switch_;
}
public void setSwitch_(boolean switch_)
{
this.switch_ = switch_;
}
public int getJumpingTimer()
{
return jumpingTimer;
}
public int getInTrickTimer()
{
return inTrickTimer;
}
public boolean isFlipped()
{
return flipped;
}
public void setFlipped()
{
this.flipped ^= true;
}
public boolean isOnAngledBlock()
{
return onAngledBlock;
}
public IBlockState getAngledBlockState()
{
return angledBlockState;
}
public Angled getAngledBlock()
{
return angledBlock;
}
public void updateAngledBlock()
{
IBlockState inside = worldObj.getBlockState(new BlockPos(posX, posY, posZ));
if(inside.getBlock() instanceof Angled)
{
this.onAngledBlock = true;
this.angledBlockState = inside;
this.angledBlock = (Angled) inside.getBlock();
return;
}
IBlockState below = worldObj.getBlockState(new BlockPos(posX, posY - 1, posZ));
if(below.getBlock() instanceof Angled)
{
this.onAngledBlock = true;
this.angledBlockState = below;
this.angledBlock = (Angled) below.getBlock();
return;
}
if(grinding)
{
IBlockState underground = worldObj.getBlockState(new BlockPos(posX, posY - 2, posZ));
if(underground.getBlock() instanceof Angled)
{
this.onAngledBlock = true;
this.angledBlockState = underground;
this.angledBlock = (Angled) underground.getBlock();
return;
}
}
this.onAngledBlock = false;
this.angledBlockState = null;
this.angledBlock = null;
}
public void setCameraUpdate(float amount)
{
this.needsCameraUpdate = true;
this.cameraIncrement = amount / 4F;
this.cameraYaw = amount;
}
@Override
public Entity getControllingPassenger()
{
if(getPassengers().size() > 0)
{
return getPassengers().get(0);
}
return null;
}
public void print()
{
EntityLivingBase entity = (EntityLivingBase) this.getControllingPassenger();
System.out.println(entity.rotationYaw - 90F);
System.out.println("Rotation Yaw:" + rotationYaw);
System.out.println("Prev Rotation Yaw:" + prevRotationYaw);
System.out.println("Current Speed: " + currentSpeed);
System.out.println("Max Speed: " + maxSpeed);
System.out.println("Allow Once: " + allowJumpOnce);
System.out.println("Pushed: " + pushed);
System.out.println("Jumping: " + jumping);
System.out.println("Jumping Timer: " + jumpingTimer);
System.out.println("Trick Timer: " + inTrickTimer);
System.out.println("Current Trick: " + currentTrick);
System.out.println("Grinding: " + grinding);
System.out.println("Goofy: " + goofy);
System.out.println("Switch: " + switch_);
System.out.println("Flipped: " + flipped);
System.out.println("Angle On Jump: " + angleOnJump);
System.out.println("Angle On Trick: " + angleOnTrick);
System.out.println("Rotation: " + rotation);
System.out.println("Board Yaw: " + boardYaw);
System.out.println("Prev Board Yaw: " + prevBoardYaw);
System.out.println("Board Rotation X: " + boardRotationX);
System.out.println("Board Rotation Y: " + boardRotationY);
System.out.println("Board Rotation Z: " + boardRotationZ);
System.out.println("Prev Board Rotation X: " + prevBoardRotationX);
System.out.println("Prev Board Rotation Y: " + prevBoardRotationY);
System.out.println("Prev Board Rotation Z: " + prevBoardRotationZ);
}
}