001package net.minecraft.entity.item;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.List;
006import net.minecraft.block.Block;
007import net.minecraft.block.BlockRailBase;
008import net.minecraft.entity.Entity;
009import net.minecraft.entity.EntityLiving;
010import net.minecraft.entity.ai.EntityMinecartMobSpawner;
011import net.minecraft.entity.monster.EntityIronGolem;
012import net.minecraft.entity.player.EntityPlayer;
013import net.minecraft.item.Item;
014import net.minecraft.item.ItemStack;
015import net.minecraft.nbt.NBTTagCompound;
016import net.minecraft.server.MinecraftServer;
017import net.minecraft.server.gui.IUpdatePlayerListBox;
018import net.minecraft.util.AxisAlignedBB;
019import net.minecraft.util.DamageSource;
020import net.minecraft.util.MathHelper;
021import net.minecraft.util.Vec3;
022import net.minecraft.world.World;
023import net.minecraft.world.WorldServer;
024import net.minecraftforge.common.IMinecartCollisionHandler;
025import net.minecraftforge.common.MinecraftForge;
026import net.minecraftforge.event.entity.minecart.MinecartCollisionEvent;
027import net.minecraftforge.event.entity.minecart.MinecartUpdateEvent;
028
029public abstract class EntityMinecart extends Entity
030{
031    protected boolean isInReverse;
032    protected final IUpdatePlayerListBox field_82344_g;
033    protected String field_94102_c;
034
035    /** Minecart rotational logic matrix */
036    protected static final int[][][] matrix = new int[][][] {{{0, 0, -1}, {0, 0, 1}}, {{ -1, 0, 0}, {1, 0, 0}}, {{ -1, -1, 0}, {1, 0, 0}}, {{ -1, 0, 0}, {1, -1, 0}}, {{0, 0, -1}, {0, -1, 1}}, {{0, -1, -1}, {0, 0, 1}}, {{0, 0, 1}, {1, 0, 0}}, {{0, 0, 1}, { -1, 0, 0}}, {{0, 0, -1}, { -1, 0, 0}}, {{0, 0, -1}, {1, 0, 0}}};
037
038    /** appears to be the progress of the turn */
039    protected int turnProgress;
040    protected double minecartX;
041    protected double minecartY;
042    protected double minecartZ;
043    protected double minecartYaw;
044    protected double minecartPitch;
045    @SideOnly(Side.CLIENT)
046    protected double velocityX;
047    @SideOnly(Side.CLIENT)
048    protected double velocityY;
049    @SideOnly(Side.CLIENT)
050    protected double velocityZ;
051
052    /* Forge: Minecart Compatibility Layer Integration. */
053    public static float defaultMaxSpeedAirLateral = 0.4f;
054    public static float defaultMaxSpeedAirVertical = -1f;
055    public static double defaultDragAir = 0.94999998807907104D;
056    protected boolean canUseRail = true;
057    protected boolean canBePushed = true;
058    private static IMinecartCollisionHandler collisionHandler = null;
059
060    /* Instance versions of the above physics properties */
061    private float currentSpeedRail = getMaxCartSpeedOnRail();
062    protected float maxSpeedAirLateral = defaultMaxSpeedAirLateral;
063    protected float maxSpeedAirVertical = defaultMaxSpeedAirVertical;
064    protected double dragAir = defaultDragAir;
065
066    public EntityMinecart(World par1World)
067    {
068        super(par1World);
069        this.isInReverse = false;
070        this.preventEntitySpawning = true;
071        this.setSize(0.98F, 0.7F);
072        this.yOffset = this.height / 2.0F;
073        this.field_82344_g = par1World != null ? par1World.func_82735_a(this) : null;
074    }
075
076    public static EntityMinecart func_94090_a(World par0World, double par1, double par3, double par5, int par7)
077    {
078        switch (par7)
079        {
080            case 1:
081                return new EntityMinecartChest(par0World, par1, par3, par5);
082            case 2:
083                return new EntityMinecartFurnace(par0World, par1, par3, par5);
084            case 3:
085                return new EntityMinecartTNT(par0World, par1, par3, par5);
086            case 4:
087                return new EntityMinecartMobSpawner(par0World, par1, par3, par5);
088            case 5:
089                return new EntityMinecartHopper(par0World, par1, par3, par5);
090            default:
091                return new EntityMinecartEmpty(par0World, par1, par3, par5);
092        }
093    }
094
095    /**
096     * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
097     * prevent them from trampling crops
098     */
099    protected boolean canTriggerWalking()
100    {
101        return false;
102    }
103
104    protected void entityInit()
105    {
106        this.dataWatcher.addObject(17, new Integer(0));
107        this.dataWatcher.addObject(18, new Integer(1));
108        this.dataWatcher.addObject(19, new Integer(0));
109        this.dataWatcher.addObject(20, new Integer(0));
110        this.dataWatcher.addObject(21, new Integer(6));
111        this.dataWatcher.addObject(22, Byte.valueOf((byte)0));
112    }
113
114    /**
115     * Returns a boundingBox used to collide the entity with other entities and blocks. This enables the entity to be
116     * pushable on contact, like boats or minecarts.
117     */
118    public AxisAlignedBB getCollisionBox(Entity par1Entity)
119    {
120        if (getCollisionHandler() != null)
121        {
122            return getCollisionHandler().getCollisionBox(this, par1Entity);
123        }
124        return par1Entity.canBePushed() ? par1Entity.boundingBox : null;
125    }
126
127    /**
128     * returns the bounding box for this entity
129     */
130    public AxisAlignedBB getBoundingBox()
131    {
132        if (getCollisionHandler() != null)
133        {
134            return getCollisionHandler().getBoundingBox(this);
135        }
136        return null;
137    }
138
139    /**
140     * Returns true if this entity should push and be pushed by other entities when colliding.
141     */
142    public boolean canBePushed()
143    {
144        return canBePushed;
145    }
146
147    public EntityMinecart(World par1World, double par2, double par4, double par6)
148    {
149        this(par1World);
150        this.setPosition(par2, par4 + (double)this.yOffset, par6);
151        this.motionX = 0.0D;
152        this.motionY = 0.0D;
153        this.motionZ = 0.0D;
154        this.prevPosX = par2;
155        this.prevPosY = par4;
156        this.prevPosZ = par6;
157    }
158
159    /**
160     * Returns the Y offset from the entity's position for any entity riding this one.
161     */
162    public double getMountedYOffset()
163    {
164        return (double)this.height * 0.0D - 0.30000001192092896D;
165    }
166
167    /**
168     * Called when the entity is attacked.
169     */
170    public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
171    {
172        if (!this.worldObj.isRemote && !this.isDead)
173        {
174            if (this.isEntityInvulnerable())
175            {
176                return false;
177            }
178            else
179            {
180                this.setRollingDirection(-this.getRollingDirection());
181                this.setRollingAmplitude(10);
182                this.setBeenAttacked();
183                this.setDamage(this.getDamage() + par2 * 10);
184                boolean flag = par1DamageSource.getEntity() instanceof EntityPlayer && ((EntityPlayer)par1DamageSource.getEntity()).capabilities.isCreativeMode;
185
186                if (flag || this.getDamage() > 40)
187                {
188                    if (this.riddenByEntity != null)
189                    {
190                        this.riddenByEntity.mountEntity(this);
191                    }
192
193                    if (flag && !this.isInvNameLocalized())
194                    {
195                        this.setDead();
196                    }
197                    else
198                    {
199                        this.func_94095_a(par1DamageSource);
200                    }
201                }
202
203                return true;
204            }
205        }
206        else
207        {
208            return true;
209        }
210    }
211
212    public void func_94095_a(DamageSource par1DamageSource)
213    {
214        this.setDead();
215        ItemStack itemstack = new ItemStack(Item.minecartEmpty, 1);
216
217        if (this.field_94102_c != null)
218        {
219            itemstack.setItemName(this.field_94102_c);
220        }
221
222        this.entityDropItem(itemstack, 0.0F);
223    }
224
225    @SideOnly(Side.CLIENT)
226
227    /**
228     * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
229     */
230    public void performHurtAnimation()
231    {
232        this.setRollingDirection(-this.getRollingDirection());
233        this.setRollingAmplitude(10);
234        this.setDamage(this.getDamage() + this.getDamage() * 10);
235    }
236
237    /**
238     * Returns true if other Entities should be prevented from moving through this Entity.
239     */
240    public boolean canBeCollidedWith()
241    {
242        return !this.isDead;
243    }
244
245    /**
246     * Will get destroyed next tick.
247     */
248    public void setDead()
249    {
250        super.setDead();
251
252        if (this.field_82344_g != null)
253        {
254            this.field_82344_g.update();
255        }
256    }
257
258    /**
259     * Called to update the entity's position/logic.
260     */
261    public void onUpdate()
262    {
263        if (this.field_82344_g != null)
264        {
265            this.field_82344_g.update();
266        }
267
268        if (this.getRollingAmplitude() > 0)
269        {
270            this.setRollingAmplitude(this.getRollingAmplitude() - 1);
271        }
272
273        if (this.getDamage() > 0)
274        {
275            this.setDamage(this.getDamage() - 1);
276        }
277
278        if (this.posY < -64.0D)
279        {
280            this.kill();
281        }
282
283        int i;
284
285        if (!this.worldObj.isRemote && this.worldObj instanceof WorldServer)
286        {
287            this.worldObj.theProfiler.startSection("portal");
288            MinecraftServer minecraftserver = ((WorldServer)this.worldObj).getMinecraftServer();
289            i = this.getMaxInPortalTime();
290
291            if (this.inPortal)
292            {
293                if (minecraftserver.getAllowNether())
294                {
295                    if (this.ridingEntity == null && this.timeInPortal++ >= i)
296                    {
297                        this.timeInPortal = i;
298                        this.timeUntilPortal = this.getPortalCooldown();
299                        byte b0;
300
301                        if (this.worldObj.provider.dimensionId == -1)
302                        {
303                            b0 = 0;
304                        }
305                        else
306                        {
307                            b0 = -1;
308                        }
309
310                        this.travelToDimension(b0);
311                    }
312
313                    this.inPortal = false;
314                }
315            }
316            else
317            {
318                if (this.timeInPortal > 0)
319                {
320                    this.timeInPortal -= 4;
321                }
322
323                if (this.timeInPortal < 0)
324                {
325                    this.timeInPortal = 0;
326                }
327            }
328
329            if (this.timeUntilPortal > 0)
330            {
331                --this.timeUntilPortal;
332            }
333
334            this.worldObj.theProfiler.endSection();
335        }
336
337        if (this.worldObj.isRemote)
338        {
339            if (this.turnProgress > 0)
340            {
341                double d0 = this.posX + (this.minecartX - this.posX) / (double)this.turnProgress;
342                double d1 = this.posY + (this.minecartY - this.posY) / (double)this.turnProgress;
343                double d2 = this.posZ + (this.minecartZ - this.posZ) / (double)this.turnProgress;
344                double d3 = MathHelper.wrapAngleTo180_double(this.minecartYaw - (double)this.rotationYaw);
345                this.rotationYaw = (float)((double)this.rotationYaw + d3 / (double)this.turnProgress);
346                this.rotationPitch = (float)((double)this.rotationPitch + (this.minecartPitch - (double)this.rotationPitch) / (double)this.turnProgress);
347                --this.turnProgress;
348                this.setPosition(d0, d1, d2);
349                this.setRotation(this.rotationYaw, this.rotationPitch);
350            }
351            else
352            {
353                this.setPosition(this.posX, this.posY, this.posZ);
354                this.setRotation(this.rotationYaw, this.rotationPitch);
355            }
356        }
357        else
358        {
359            this.prevPosX = this.posX;
360            this.prevPosY = this.posY;
361            this.prevPosZ = this.posZ;
362            this.motionY -= 0.03999999910593033D;
363            int j = MathHelper.floor_double(this.posX);
364            i = MathHelper.floor_double(this.posY);
365            int k = MathHelper.floor_double(this.posZ);
366
367            if (BlockRailBase.isRailBlockAt(this.worldObj, j, i - 1, k))
368            {
369                --i;
370            }
371
372            double d4 = 0.4D;
373            double d5 = 0.0078125D;
374            int l = this.worldObj.getBlockId(j, i, k);
375
376            if (canUseRail() && BlockRailBase.isRailBlock(l))
377            {
378                BlockRailBase rail = (BlockRailBase)Block.blocksList[l];
379                float railMaxSpeed = rail.getRailMaxSpeed(worldObj, this, j, i, k);
380                double maxSpeed = Math.min(railMaxSpeed, getCurrentCartSpeedCapOnRail());
381                int i1 = rail.getBasicRailMetadata(worldObj, this, j, i, k);
382                this.func_94091_a(j, i, k, maxSpeed, getSlopeAdjustment(), l, i1);
383
384                if (l == Block.railActivator.blockID)
385                {
386                    this.func_96095_a(j, i, k, (worldObj.getBlockMetadata(j, i, k) & 8) != 0);
387                }
388            }
389            else
390            {
391                this.func_94088_b(onGround ? d4 : getMaxSpeedAirLateral());
392            }
393
394            this.doBlockCollisions();
395            this.rotationPitch = 0.0F;
396            double d6 = this.prevPosX - this.posX;
397            double d7 = this.prevPosZ - this.posZ;
398
399            if (d6 * d6 + d7 * d7 > 0.001D)
400            {
401                this.rotationYaw = (float)(Math.atan2(d7, d6) * 180.0D / Math.PI);
402
403                if (this.isInReverse)
404                {
405                    this.rotationYaw += 180.0F;
406                }
407            }
408
409            double d8 = (double)MathHelper.wrapAngleTo180_float(this.rotationYaw - this.prevRotationYaw);
410
411            if (d8 < -170.0D || d8 >= 170.0D)
412            {
413                this.rotationYaw += 180.0F;
414                this.isInReverse = !this.isInReverse;
415            }
416
417            this.setRotation(this.rotationYaw, this.rotationPitch);
418
419            AxisAlignedBB box;
420            if (getCollisionHandler() != null)
421            {
422                box = getCollisionHandler().getMinecartCollisionBox(this);
423            }
424            else
425            {
426                box = boundingBox.expand(0.2D, 0.0D, 0.2D);
427            }
428
429            List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, box);
430
431            if (list != null && !list.isEmpty())
432            {
433                for (int j1 = 0; j1 < list.size(); ++j1)
434                {
435                    Entity entity = (Entity)list.get(j1);
436
437                    if (entity != this.riddenByEntity && entity.canBePushed() && entity instanceof EntityMinecart)
438                    {
439                        entity.applyEntityCollision(this);
440                    }
441                }
442            }
443
444            if (this.riddenByEntity != null && this.riddenByEntity.isDead)
445            {
446                if (this.riddenByEntity.ridingEntity == this)
447                {
448                    this.riddenByEntity.ridingEntity = null;
449                }
450
451                this.riddenByEntity = null;
452            }
453
454            MinecraftForge.EVENT_BUS.post(new MinecartUpdateEvent(this, j, i, k));
455        }
456    }
457
458    public void func_96095_a(int par1, int par2, int par3, boolean par4) {}
459
460    protected void func_94088_b(double par1)
461    {
462        if (this.motionX < -par1)
463        {
464            this.motionX = -par1;
465        }
466
467        if (this.motionX > par1)
468        {
469            this.motionX = par1;
470        }
471
472        if (this.motionZ < -par1)
473        {
474            this.motionZ = -par1;
475        }
476
477        if (this.motionZ > par1)
478        {
479            this.motionZ = par1;
480        }
481
482        double moveY = motionY;
483        if(getMaxSpeedAirVertical() > 0 && motionY > getMaxSpeedAirVertical())
484        {
485            moveY = getMaxSpeedAirVertical();
486            if(Math.abs(motionX) < 0.3f && Math.abs(motionZ) < 0.3f)
487            {
488                moveY = 0.15f;
489                motionY = moveY;
490            }
491        }
492
493        if (this.onGround)
494        {
495            this.motionX *= 0.5D;
496            this.motionY *= 0.5D;
497            this.motionZ *= 0.5D;
498        }
499
500        this.moveEntity(this.motionX, moveY, this.motionZ);
501
502        if (!this.onGround)
503        {
504            this.motionX *= getDragAir();
505            this.motionY *= getDragAir();
506            this.motionZ *= getDragAir();
507        }
508    }
509
510    protected void func_94091_a(int par1, int par2, int par3, double par4, double par6, int par8, int par9)
511    {
512        this.fallDistance = 0.0F;
513        Vec3 vec3 = this.func_70489_a(this.posX, this.posY, this.posZ);
514        this.posY = (double)par2;
515        boolean flag = false;
516        boolean flag1 = false;
517
518        if (par8 == Block.railPowered.blockID)
519        {
520            flag = (worldObj.getBlockMetadata(par1, par2, par3) & 8) != 0;
521            flag1 = !flag;
522        }
523
524        if (((BlockRailBase)Block.blocksList[par8]).isPowered())
525        {
526            par9 &= 7;
527        }
528
529        if (par9 >= 2 && par9 <= 5)
530        {
531            this.posY = (double)(par2 + 1);
532        }
533
534        if (par9 == 2)
535        {
536            this.motionX -= par6;
537        }
538
539        if (par9 == 3)
540        {
541            this.motionX += par6;
542        }
543
544        if (par9 == 4)
545        {
546            this.motionZ += par6;
547        }
548
549        if (par9 == 5)
550        {
551            this.motionZ -= par6;
552        }
553
554        int[][] aint = matrix[par9];
555        double d2 = (double)(aint[1][0] - aint[0][0]);
556        double d3 = (double)(aint[1][2] - aint[0][2]);
557        double d4 = Math.sqrt(d2 * d2 + d3 * d3);
558        double d5 = this.motionX * d2 + this.motionZ * d3;
559
560        if (d5 < 0.0D)
561        {
562            d2 = -d2;
563            d3 = -d3;
564        }
565
566        double d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
567
568        if (d6 > 2.0D)
569        {
570            d6 = 2.0D;
571        }
572
573        this.motionX = d6 * d2 / d4;
574        this.motionZ = d6 * d3 / d4;
575        double d7;
576        double d8;
577
578        if (this.riddenByEntity != null)
579        {
580            d7 = this.riddenByEntity.motionX * this.riddenByEntity.motionX + this.riddenByEntity.motionZ * this.riddenByEntity.motionZ;
581            d8 = this.motionX * this.motionX + this.motionZ * this.motionZ;
582
583            if (d7 > 1.0E-4D && d8 < 0.01D)
584            {
585                this.motionX += this.riddenByEntity.motionX * 0.1D;
586                this.motionZ += this.riddenByEntity.motionZ * 0.1D;
587                flag1 = false;
588            }
589        }
590
591        if (flag1 && shouldDoRailFunctions())
592        {
593            d7 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
594
595            if (d7 < 0.03D)
596            {
597                this.motionX *= 0.0D;
598                this.motionY *= 0.0D;
599                this.motionZ *= 0.0D;
600            }
601            else
602            {
603                this.motionX *= 0.5D;
604                this.motionY *= 0.0D;
605                this.motionZ *= 0.5D;
606            }
607        }
608
609        d7 = 0.0D;
610        d8 = (double)par1 + 0.5D + (double)aint[0][0] * 0.5D;
611        double d9 = (double)par3 + 0.5D + (double)aint[0][2] * 0.5D;
612        double d10 = (double)par1 + 0.5D + (double)aint[1][0] * 0.5D;
613        double d11 = (double)par3 + 0.5D + (double)aint[1][2] * 0.5D;
614        d2 = d10 - d8;
615        d3 = d11 - d9;
616        double d12;
617        double d13;
618
619        if (d2 == 0.0D)
620        {
621            this.posX = (double)par1 + 0.5D;
622            d7 = this.posZ - (double)par3;
623        }
624        else if (d3 == 0.0D)
625        {
626            this.posZ = (double)par3 + 0.5D;
627            d7 = this.posX - (double)par1;
628        }
629        else
630        {
631            d12 = this.posX - d8;
632            d13 = this.posZ - d9;
633            d7 = (d12 * d2 + d13 * d3) * 2.0D;
634        }
635
636        this.posX = d8 + d2 * d7;
637        this.posZ = d9 + d3 * d7;
638        this.setPosition(this.posX, this.posY + (double)this.yOffset, this.posZ);
639
640        moveMinecartOnRail(par1, par2, par3, par4);
641
642        if (aint[0][1] != 0 && MathHelper.floor_double(this.posX) - par1 == aint[0][0] && MathHelper.floor_double(this.posZ) - par3 == aint[0][2])
643        {
644            this.setPosition(this.posX, this.posY + (double)aint[0][1], this.posZ);
645        }
646        else if (aint[1][1] != 0 && MathHelper.floor_double(this.posX) - par1 == aint[1][0] && MathHelper.floor_double(this.posZ) - par3 == aint[1][2])
647        {
648            this.setPosition(this.posX, this.posY + (double)aint[1][1], this.posZ);
649        }
650
651        this.func_94101_h();
652        Vec3 vec31 = this.func_70489_a(this.posX, this.posY, this.posZ);
653
654        if (vec31 != null && vec3 != null)
655        {
656            double d14 = (vec3.yCoord - vec31.yCoord) * 0.05D;
657            d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
658
659            if (d6 > 0.0D)
660            {
661                this.motionX = this.motionX / d6 * (d6 + d14);
662                this.motionZ = this.motionZ / d6 * (d6 + d14);
663            }
664
665            this.setPosition(this.posX, vec31.yCoord, this.posZ);
666        }
667
668        int j1 = MathHelper.floor_double(this.posX);
669        int k1 = MathHelper.floor_double(this.posZ);
670
671        if (j1 != par1 || k1 != par3)
672        {
673            d6 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
674            this.motionX = d6 * (double)(j1 - par1);
675            this.motionZ = d6 * (double)(k1 - par3);
676        }
677
678        if(shouldDoRailFunctions())
679        {
680            ((BlockRailBase)Block.blocksList[par8]).onMinecartPass(worldObj, this, par1, par2, par3);
681        }
682
683        if (flag && shouldDoRailFunctions())
684        {
685            double d15 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
686
687            if (d15 > 0.01D)
688            {
689                double d16 = 0.06D;
690                this.motionX += this.motionX / d15 * d16;
691                this.motionZ += this.motionZ / d15 * d16;
692            }
693            else if (par9 == 1)
694            {
695                if (this.worldObj.isBlockNormalCube(par1 - 1, par2, par3))
696                {
697                    this.motionX = 0.02D;
698                }
699                else if (this.worldObj.isBlockNormalCube(par1 + 1, par2, par3))
700                {
701                    this.motionX = -0.02D;
702                }
703            }
704            else if (par9 == 0)
705            {
706                if (this.worldObj.isBlockNormalCube(par1, par2, par3 - 1))
707                {
708                    this.motionZ = 0.02D;
709                }
710                else if (this.worldObj.isBlockNormalCube(par1, par2, par3 + 1))
711                {
712                    this.motionZ = -0.02D;
713                }
714            }
715        }
716    }
717
718    protected void func_94101_h()
719    {
720        if (this.riddenByEntity != null)
721        {
722            this.motionX *= 0.996999979019165D;
723            this.motionY *= 0.0D;
724            this.motionZ *= 0.996999979019165D;
725        }
726        else
727        {
728            this.motionX *= 0.9599999785423279D;
729            this.motionY *= 0.0D;
730            this.motionZ *= 0.9599999785423279D;
731        }
732    }
733
734    @SideOnly(Side.CLIENT)
735    public Vec3 func_70495_a(double par1, double par3, double par5, double par7)
736    {
737        int i = MathHelper.floor_double(par1);
738        int j = MathHelper.floor_double(par3);
739        int k = MathHelper.floor_double(par5);
740
741        if (BlockRailBase.isRailBlockAt(this.worldObj, i, j - 1, k))
742        {
743            --j;
744        }
745
746        int l = this.worldObj.getBlockId(i, j, k);
747
748        if (!BlockRailBase.isRailBlock(l))
749        {
750            return null;
751        }
752        else
753        {
754            int i1 = ((BlockRailBase)Block.blocksList[l]).getBasicRailMetadata(worldObj, this, i, j, k);
755
756            par3 = (double)j;
757
758            if (i1 >= 2 && i1 <= 5)
759            {
760                par3 = (double)(j + 1);
761            }
762
763            int[][] aint = matrix[i1];
764            double d4 = (double)(aint[1][0] - aint[0][0]);
765            double d5 = (double)(aint[1][2] - aint[0][2]);
766            double d6 = Math.sqrt(d4 * d4 + d5 * d5);
767            d4 /= d6;
768            d5 /= d6;
769            par1 += d4 * par7;
770            par5 += d5 * par7;
771
772            if (aint[0][1] != 0 && MathHelper.floor_double(par1) - i == aint[0][0] && MathHelper.floor_double(par5) - k == aint[0][2])
773            {
774                par3 += (double)aint[0][1];
775            }
776            else if (aint[1][1] != 0 && MathHelper.floor_double(par1) - i == aint[1][0] && MathHelper.floor_double(par5) - k == aint[1][2])
777            {
778                par3 += (double)aint[1][1];
779            }
780
781            return this.func_70489_a(par1, par3, par5);
782        }
783    }
784
785    public Vec3 func_70489_a(double par1, double par3, double par5)
786    {
787        int i = MathHelper.floor_double(par1);
788        int j = MathHelper.floor_double(par3);
789        int k = MathHelper.floor_double(par5);
790
791        if (BlockRailBase.isRailBlockAt(this.worldObj, i, j - 1, k))
792        {
793            --j;
794        }
795
796        int l = this.worldObj.getBlockId(i, j, k);
797
798        if (BlockRailBase.isRailBlock(l))
799        {
800            int i1 = ((BlockRailBase)Block.blocksList[l]).getBasicRailMetadata(worldObj, this, i, j, k);
801            par3 = (double)j;
802
803            if (i1 >= 2 && i1 <= 5)
804            {
805                par3 = (double)(j + 1);
806            }
807
808            int[][] aint = matrix[i1];
809            double d3 = 0.0D;
810            double d4 = (double)i + 0.5D + (double)aint[0][0] * 0.5D;
811            double d5 = (double)j + 0.5D + (double)aint[0][1] * 0.5D;
812            double d6 = (double)k + 0.5D + (double)aint[0][2] * 0.5D;
813            double d7 = (double)i + 0.5D + (double)aint[1][0] * 0.5D;
814            double d8 = (double)j + 0.5D + (double)aint[1][1] * 0.5D;
815            double d9 = (double)k + 0.5D + (double)aint[1][2] * 0.5D;
816            double d10 = d7 - d4;
817            double d11 = (d8 - d5) * 2.0D;
818            double d12 = d9 - d6;
819
820            if (d10 == 0.0D)
821            {
822                par1 = (double)i + 0.5D;
823                d3 = par5 - (double)k;
824            }
825            else if (d12 == 0.0D)
826            {
827                par5 = (double)k + 0.5D;
828                d3 = par1 - (double)i;
829            }
830            else
831            {
832                double d13 = par1 - d4;
833                double d14 = par5 - d6;
834                d3 = (d13 * d10 + d14 * d12) * 2.0D;
835            }
836
837            par1 = d4 + d10 * d3;
838            par3 = d5 + d11 * d3;
839            par5 = d6 + d12 * d3;
840
841            if (d11 < 0.0D)
842            {
843                ++par3;
844            }
845
846            if (d11 > 0.0D)
847            {
848                par3 += 0.5D;
849            }
850
851            return this.worldObj.getWorldVec3Pool().getVecFromPool(par1, par3, par5);
852        }
853        else
854        {
855            return null;
856        }
857    }
858
859    /**
860     * (abstract) Protected helper method to read subclass entity data from NBT.
861     */
862    protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
863    {
864        if (par1NBTTagCompound.getBoolean("CustomDisplayTile"))
865        {
866            this.func_94094_j(par1NBTTagCompound.getInteger("DisplayTile"));
867            this.func_94092_k(par1NBTTagCompound.getInteger("DisplayData"));
868            this.func_94086_l(par1NBTTagCompound.getInteger("DisplayOffset"));
869        }
870
871        if (par1NBTTagCompound.hasKey("CustomName") && par1NBTTagCompound.getString("CustomName").length() > 0)
872        {
873            this.field_94102_c = par1NBTTagCompound.getString("CustomName");
874        }
875    }
876
877    /**
878     * (abstract) Protected helper method to write subclass entity data to NBT.
879     */
880    protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
881    {
882        if (this.func_94100_s())
883        {
884            par1NBTTagCompound.setBoolean("CustomDisplayTile", true);
885            par1NBTTagCompound.setInteger("DisplayTile", this.func_94089_m() == null ? 0 : this.func_94089_m().blockID);
886            par1NBTTagCompound.setInteger("DisplayData", this.func_94098_o());
887            par1NBTTagCompound.setInteger("DisplayOffset", this.func_94099_q());
888        }
889
890        if (this.field_94102_c != null && this.field_94102_c.length() > 0)
891        {
892            par1NBTTagCompound.setString("CustomName", this.field_94102_c);
893        }
894    }
895
896    @SideOnly(Side.CLIENT)
897    public float getShadowSize()
898    {
899        return 0.0F;
900    }
901
902    /**
903     * Applies a velocity to each of the entities pushing them away from each other. Args: entity
904     */
905    public void applyEntityCollision(Entity par1Entity)
906    {
907        MinecraftForge.EVENT_BUS.post(new MinecartCollisionEvent(this, par1Entity));
908        if (getCollisionHandler() != null)
909        {
910            getCollisionHandler().onEntityCollision(this, par1Entity);
911            return;
912        }
913        if (!this.worldObj.isRemote)
914        {
915            if (par1Entity != this.riddenByEntity)
916            {
917                if (par1Entity instanceof EntityLiving && !(par1Entity instanceof EntityPlayer) && !(par1Entity instanceof EntityIronGolem) && canBeRidden() && this.motionX * this.motionX + this.motionZ * this.motionZ > 0.01D && this.riddenByEntity == null && par1Entity.ridingEntity == null)
918                {
919                    par1Entity.mountEntity(this);
920                }
921
922                double d0 = par1Entity.posX - this.posX;
923                double d1 = par1Entity.posZ - this.posZ;
924                double d2 = d0 * d0 + d1 * d1;
925
926                if (d2 >= 9.999999747378752E-5D)
927                {
928                    d2 = (double)MathHelper.sqrt_double(d2);
929                    d0 /= d2;
930                    d1 /= d2;
931                    double d3 = 1.0D / d2;
932
933                    if (d3 > 1.0D)
934                    {
935                        d3 = 1.0D;
936                    }
937
938                    d0 *= d3;
939                    d1 *= d3;
940                    d0 *= 0.10000000149011612D;
941                    d1 *= 0.10000000149011612D;
942                    d0 *= (double)(1.0F - this.entityCollisionReduction);
943                    d1 *= (double)(1.0F - this.entityCollisionReduction);
944                    d0 *= 0.5D;
945                    d1 *= 0.5D;
946
947                    if (par1Entity instanceof EntityMinecart)
948                    {
949                        double d4 = par1Entity.posX - this.posX;
950                        double d5 = par1Entity.posZ - this.posZ;
951                        Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(d4, 0.0D, d5).normalize();
952                        Vec3 vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool((double)MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F), 0.0D, (double)MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F)).normalize();
953                        double d6 = Math.abs(vec3.dotProduct(vec31));
954
955                        if (d6 < 0.800000011920929D)
956                        {
957                            return;
958                        }
959
960                        double d7 = par1Entity.motionX + this.motionX;
961                        double d8 = par1Entity.motionZ + this.motionZ;
962
963                        if (((EntityMinecart)par1Entity).isPoweredCart() && !isPoweredCart())
964                        {
965                            this.motionX *= 0.20000000298023224D;
966                            this.motionZ *= 0.20000000298023224D;
967                            this.addVelocity(par1Entity.motionX - d0, 0.0D, par1Entity.motionZ - d1);
968                            par1Entity.motionX *= 0.949999988079071D;
969                            par1Entity.motionZ *= 0.949999988079071D;
970                        }
971                        else if (!((EntityMinecart)par1Entity).isPoweredCart() && isPoweredCart())
972                        {
973                            par1Entity.motionX *= 0.20000000298023224D;
974                            par1Entity.motionZ *= 0.20000000298023224D;
975                            par1Entity.addVelocity(this.motionX + d0, 0.0D, this.motionZ + d1);
976                            this.motionX *= 0.949999988079071D;
977                            this.motionZ *= 0.949999988079071D;
978                        }
979                        else
980                        {
981                            d7 /= 2.0D;
982                            d8 /= 2.0D;
983                            this.motionX *= 0.20000000298023224D;
984                            this.motionZ *= 0.20000000298023224D;
985                            this.addVelocity(d7 - d0, 0.0D, d8 - d1);
986                            par1Entity.motionX *= 0.20000000298023224D;
987                            par1Entity.motionZ *= 0.20000000298023224D;
988                            par1Entity.addVelocity(d7 + d0, 0.0D, d8 + d1);
989                        }
990                    }
991                    else
992                    {
993                        this.addVelocity(-d0, 0.0D, -d1);
994                        par1Entity.addVelocity(d0 / 4.0D, 0.0D, d1 / 4.0D);
995                    }
996                }
997            }
998        }
999    }
1000
1001    @SideOnly(Side.CLIENT)
1002
1003    /**
1004     * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
1005     * posY, posZ, yaw, pitch
1006     */
1007    public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
1008    {
1009        this.minecartX = par1;
1010        this.minecartY = par3;
1011        this.minecartZ = par5;
1012        this.minecartYaw = (double)par7;
1013        this.minecartPitch = (double)par8;
1014        this.turnProgress = par9 + 2;
1015        this.motionX = this.velocityX;
1016        this.motionY = this.velocityY;
1017        this.motionZ = this.velocityZ;
1018    }
1019
1020    @SideOnly(Side.CLIENT)
1021
1022    /**
1023     * Sets the velocity to the args. Args: x, y, z
1024     */
1025    public void setVelocity(double par1, double par3, double par5)
1026    {
1027        this.velocityX = this.motionX = par1;
1028        this.velocityY = this.motionY = par3;
1029        this.velocityZ = this.motionZ = par5;
1030    }
1031
1032    /**
1033     * Sets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over
1034     * 40.
1035     */
1036    public void setDamage(int par1)
1037    {
1038        this.dataWatcher.updateObject(19, Integer.valueOf(par1));
1039    }
1040
1041    /**
1042     * Gets the current amount of damage the minecart has taken. Decreases over time. The cart breaks when this is over
1043     * 40.
1044     */
1045    public int getDamage()
1046    {
1047        return this.dataWatcher.getWatchableObjectInt(19);
1048    }
1049
1050    /**
1051     * Sets the rolling amplitude the cart rolls while being attacked.
1052     */
1053    public void setRollingAmplitude(int par1)
1054    {
1055        this.dataWatcher.updateObject(17, Integer.valueOf(par1));
1056    }
1057
1058    /**
1059     * Gets the rolling amplitude the cart rolls while being attacked.
1060     */
1061    public int getRollingAmplitude()
1062    {
1063        return this.dataWatcher.getWatchableObjectInt(17);
1064    }
1065
1066    /**
1067     * Sets the rolling direction the cart rolls while being attacked. Can be 1 or -1.
1068     */
1069    public void setRollingDirection(int par1)
1070    {
1071        this.dataWatcher.updateObject(18, Integer.valueOf(par1));
1072    }
1073
1074    /**
1075     * Gets the rolling direction the cart rolls while being attacked. Can be 1 or -1.
1076     */
1077    public int getRollingDirection()
1078    {
1079        return this.dataWatcher.getWatchableObjectInt(18);
1080    }
1081
1082    public abstract int func_94087_l();
1083
1084    public Block func_94089_m()
1085    {
1086        if (!this.func_94100_s())
1087        {
1088            return this.func_94093_n();
1089        }
1090        else
1091        {
1092            int i = this.getDataWatcher().getWatchableObjectInt(20) & 65535;
1093            return i > 0 && i < Block.blocksList.length ? Block.blocksList[i] : null;
1094        }
1095    }
1096
1097    public Block func_94093_n()
1098    {
1099        return null;
1100    }
1101
1102    public int func_94098_o()
1103    {
1104        return !this.func_94100_s() ? this.func_94097_p() : this.getDataWatcher().getWatchableObjectInt(20) >> 16;
1105    }
1106
1107    public int func_94097_p()
1108    {
1109        return 0;
1110    }
1111
1112    public int func_94099_q()
1113    {
1114        return !this.func_94100_s() ? this.func_94085_r() : this.getDataWatcher().getWatchableObjectInt(21);
1115    }
1116
1117    public int func_94085_r()
1118    {
1119        return 6;
1120    }
1121
1122    public void func_94094_j(int par1)
1123    {
1124        this.getDataWatcher().updateObject(20, Integer.valueOf(par1 & 65535 | this.func_94098_o() << 16));
1125        this.func_94096_e(true);
1126    }
1127
1128    public void func_94092_k(int par1)
1129    {
1130        Block block = this.func_94089_m();
1131        int j = block == null ? 0 : block.blockID;
1132        this.getDataWatcher().updateObject(20, Integer.valueOf(j & 65535 | par1 << 16));
1133        this.func_94096_e(true);
1134    }
1135
1136    public void func_94086_l(int par1)
1137    {
1138        this.getDataWatcher().updateObject(21, Integer.valueOf(par1));
1139        this.func_94096_e(true);
1140    }
1141
1142    public boolean func_94100_s()
1143    {
1144        return this.getDataWatcher().getWatchableObjectByte(22) == 1;
1145    }
1146
1147    public void func_94096_e(boolean par1)
1148    {
1149        this.getDataWatcher().updateObject(22, Byte.valueOf((byte)(par1 ? 1 : 0)));
1150    }
1151
1152    public void func_96094_a(String par1Str)
1153    {
1154        this.field_94102_c = par1Str;
1155    }
1156
1157    /**
1158     * Gets the username of the entity.
1159     */
1160    public String getEntityName()
1161    {
1162        return this.field_94102_c != null ? this.field_94102_c : super.getEntityName();
1163    }
1164
1165    /**
1166     * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's
1167     * language. Otherwise it will be used directly.
1168     */
1169    public boolean isInvNameLocalized()
1170    {
1171        return this.field_94102_c != null;
1172    }
1173
1174    public String func_95999_t()
1175    {
1176        return this.field_94102_c;
1177    }
1178
1179    /**
1180     * Moved to allow overrides.
1181     * This code handles minecart movement and speed capping when on a rail.
1182     */
1183    public void moveMinecartOnRail(int x, int y, int z, double par4){
1184        double d12 = this.motionX;
1185        double d13 = this.motionZ;
1186
1187        if (this.riddenByEntity != null)
1188        {
1189            d12 *= 0.75D;
1190            d13 *= 0.75D;
1191        }
1192
1193        if (d12 < -par4)
1194        {
1195            d12 = -par4;
1196        }
1197
1198        if (d12 > par4)
1199        {
1200            d12 = par4;
1201        }
1202
1203        if (d13 < -par4)
1204        {
1205            d13 = -par4;
1206        }
1207
1208        if (d13 > par4)
1209        {
1210            d13 = par4;
1211        }
1212
1213        this.moveEntity(d12, 0.0D, d13);
1214    }
1215
1216    /**
1217     * Gets the current global Minecart Collision handler if none
1218     * is registered, returns null
1219     * @return The collision handler or null
1220     */
1221    public static IMinecartCollisionHandler getCollisionHandler()
1222    {
1223        return collisionHandler;
1224    }
1225
1226    /**
1227     * Sets the global Minecart Collision handler, overwrites any
1228     * that is currently set.
1229     * @param handler The new handler
1230     */
1231    public static void setCollisionHandler(IMinecartCollisionHandler handler)
1232    {
1233        collisionHandler = handler;
1234    }
1235
1236    /**
1237     * This function returns an ItemStack that represents this cart.
1238     * This should be an ItemStack that can be used by the player to place the cart,
1239     * but is not necessary the item the cart drops when destroyed.
1240     * @return An ItemStack that can be used to place the cart.
1241     */
1242    public ItemStack getCartItem()
1243    {
1244        if (this instanceof EntityMinecartChest)
1245        {
1246            return new ItemStack(Item.minecartCrate);
1247        }
1248        else if (this instanceof EntityMinecartTNT)
1249        {
1250            return new ItemStack(Item.tntMinecart);
1251        }
1252        else if (this instanceof EntityMinecartFurnace)
1253        {
1254            return new ItemStack(Item.minecartPowered);
1255        }
1256        else if (this instanceof EntityMinecartHopper)
1257        {
1258            return new ItemStack(Item.hopperMinecart);
1259        }
1260        return new ItemStack(Item.minecartEmpty);
1261    }
1262
1263    /**
1264     * Returns true if this cart can currently use rails.
1265     * This function is mainly used to gracefully detach a minecart from a rail.
1266     * @return True if the minecart can use rails.
1267     */
1268    public boolean canUseRail()
1269    {
1270        return canUseRail;
1271    }
1272
1273    /**
1274     * Set whether the minecart can use rails.
1275     * This function is mainly used to gracefully detach a minecart from a rail.
1276     * @param use Whether the minecart can currently use rails.
1277     */
1278    public void setCanUseRail(boolean use)
1279    {
1280        canUseRail = use;
1281    }
1282
1283    /**
1284     * Return false if this cart should not call onMinecartPass() and should ignore Powered Rails.
1285     * @return True if this cart should call onMinecartPass().
1286     */
1287    public boolean shouldDoRailFunctions()
1288    {
1289        return true;
1290    }
1291
1292    /**
1293     * Returns true if this cart is self propelled.
1294     * @return True if powered.
1295     */
1296    public boolean isPoweredCart()
1297    {
1298        return func_94087_l() == 2;
1299    }
1300
1301    /**
1302     * Returns true if this cart can be ridden by an Entity.
1303     * @return True if this cart can be ridden.
1304     */
1305    public boolean canBeRidden()
1306    {
1307        if(this instanceof EntityMinecartEmpty)
1308        {
1309            return true;
1310        }
1311        return false;
1312    }
1313
1314    /**
1315     * Getters/setters for physics variables
1316     */
1317
1318    /**
1319     * Returns the carts max speed when traveling on rails. Carts going faster
1320     * than 1.1 cause issues with chunk loading. Carts cant traverse slopes or
1321     * corners at greater than 0.5 - 0.6. This value is compared with the rails
1322     * max speed and the carts current speed cap to determine the carts current
1323     * max speed. A normal rail's max speed is 0.4.
1324     *
1325     * @return Carts max speed.
1326     */
1327    public float getMaxCartSpeedOnRail()
1328    {
1329        return 1.2f;
1330    }
1331
1332    /**
1333     * Returns the current speed cap for the cart when traveling on rails. This
1334     * functions differs from getMaxCartSpeedOnRail() in that it controls
1335     * current movement and cannot be overridden. The value however can never be
1336     * higher than getMaxCartSpeedOnRail().
1337     *
1338     * @return
1339     */
1340    public final float getCurrentCartSpeedCapOnRail()
1341    {
1342        return currentSpeedRail;
1343    }
1344
1345    public final void setCurrentCartSpeedCapOnRail(float value)
1346    {
1347        value = Math.min(value, getMaxCartSpeedOnRail());
1348        currentSpeedRail = value;
1349    }
1350
1351    public float getMaxSpeedAirLateral()
1352    {
1353        return maxSpeedAirLateral;
1354    }
1355
1356    public void setMaxSpeedAirLateral(float value)
1357    {
1358        maxSpeedAirLateral = value;
1359    }
1360
1361    public float getMaxSpeedAirVertical()
1362    {
1363        return maxSpeedAirVertical;
1364    }
1365
1366    public void setMaxSpeedAirVertical(float value)
1367    {
1368        maxSpeedAirVertical = value;
1369    }
1370
1371    public double getDragAir()
1372    {
1373        return dragAir;
1374    }
1375
1376    public void setDragAir(double value)
1377    {
1378        dragAir = value;
1379    }
1380
1381    public double getSlopeAdjustment()
1382    {
1383        return 0.0078125D;
1384    }
1385}