Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
23 kB · 1042 lines
C++
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042#include "stdafx.h"#include "net.minecraft.world.level.dimension.h"#include "net.minecraft.world.level.h"#include "net.minecraft.world.level.tile.h"#include "net.minecraft.world.phys.h"#include "net.minecraft.world.entity.h"#include "net.minecraft.world.entity.item.h"#include "net.minecraft.world.entity.player.h"#include "net.minecraft.world.entity.animal.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.damagesource.h"#include "..\Minecraft.Client\MinecraftServer.h"#include "..\Minecraft.Client\ServerLevel.h"#include "com.mojang.nbt.h"#include "Minecart.h"#include "SharedConstants.h"
const int Minecart::EXITS[][2][3] = { // // {{+0, +0, -1}, {+0, +0, +1}}, // 0 {{-1, +0, +0}, {+1, +0, +0}}, // 1 {{-1, -1, +0}, {+1, +0, +0}}, // 2 {{-1, +0, +0}, {+1, -1, +0}}, // 3 {{+0, +0, -1}, {+0, -1, +1}}, // 4 {{+0, -1, -1}, {+0, +0, +1}}, // 5
{{+0, +0, +1}, {+1, +0, +0}}, // 6 {{+0, +0, +1}, {-1, +0, +0}}, // 7 {{+0, +0, -1}, {-1, +0, +0}}, // 8 {{+0, +0, -1}, {+1, +0, +0}}, // 9};
void Minecart::_init(){ flipped = false;
lSteps = 0; lx = ly = lz = lyr = lxr = 0.0; lxd = lyd = lzd = 0.0;
// Java default ctor blocksBuilding = true; setSize(0.98f, 0.7f); heightOffset = bbHeight / 2.0f; soundUpdater = NULL; name = L""; //
// 4J Added m_bHasPushedCartThisTick = false;}
Minecart::Minecart(Level *level) : Entity( level ){ _init();
//soundUpdater = level != NULL ? level->makeSoundUpdater(this) : NULL;}
Minecart::~Minecart(){ delete soundUpdater;}
shared_ptr<Minecart> Minecart::createMinecart(Level *level, double x, double y, double z, int type){ switch (type) { case TYPE_CHEST: return shared_ptr<MinecartChest>( new MinecartChest(level, x, y, z) ); case TYPE_FURNACE: return shared_ptr<MinecartFurnace>( new MinecartFurnace(level, x, y, z) ); case TYPE_TNT: return shared_ptr<MinecartTNT>( new MinecartTNT(level, x, y, z) ); case TYPE_SPAWNER: return shared_ptr<MinecartSpawner>( new MinecartSpawner(level, x, y, z) ); case TYPE_HOPPER: return shared_ptr<MinecartHopper>( new MinecartHopper(level, x, y, z) ); default: return shared_ptr<MinecartRideable>( new MinecartRideable(level, x, y, z) ); }}
bool Minecart::makeStepSound(){ return false;}
void Minecart::defineSynchedData(){ entityData->define(DATA_ID_HURT, 0); entityData->define(DATA_ID_HURTDIR, 1); entityData->define(DATA_ID_DAMAGE, 0.0f); entityData->define(DATA_ID_DISPLAY_TILE, 0); entityData->define(DATA_ID_DISPLAY_OFFSET, 6); entityData->define(DATA_ID_CUSTOM_DISPLAY, (byte) 0);}
AABB *Minecart::getCollideAgainstBox(shared_ptr<Entity> entity){ if (entity->isPushable()) { return entity->bb; } return NULL;}
AABB *Minecart::getCollideBox(){ return NULL;}
bool Minecart::isPushable(){ return true;}
Minecart::Minecart(Level *level, double x, double y, double z) : Entity( level ){
_init(); setPos(x, y, z);
xd = 0; yd = 0; zd = 0;
xo = x; yo = y; zo = z;}
double Minecart::getRideHeight(){ return bbHeight * 0.0 - 0.3f;}
bool Minecart::hurt(DamageSource *source, float hurtDamage){ if (level->isClientSide || removed) return true; if (isInvulnerable()) return false;
// 4J-JEV: Fix for #88212, // Untrusted players shouldn't be able to damage minecarts or boats. if (dynamic_cast<EntityDamageSource *>(source) != NULL) { shared_ptr<Entity> attacker = source->getDirectEntity();
if ( attacker->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity( shared_from_this() )) { return false; } }
setHurtDir(-getHurtDir()); setHurtTime(10); markHurt(); setDamage(getDamage() + (hurtDamage * 10));
// 4J Stu - If someone is riding in this, then it can tick multiple times which causes the damage to // decrease too quickly. So just make the damage a bit higher to start with for similar behaviour // to an unridden one. Only do this change if the riding player is attacking it. if( rider.lock() != NULL && rider.lock() == source->getEntity() ) hurtDamage += 1;
bool creativePlayer = source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) && dynamic_pointer_cast<Player>(source->getEntity())->abilities.instabuild;
if (creativePlayer || getDamage() > 20 * 2) { // 4J HEG - Fixed issue with player falling through the ground on destroying a minecart while riding (issue #160607) if (rider.lock() != NULL) rider.lock()->ride(nullptr);
if (!creativePlayer || hasCustomName()) { destroy(source); } else { remove(); } } return true;}
void Minecart::destroy(DamageSource *source){ remove(); shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>( new ItemInstance(Item::minecart, 1) ); if (!name.empty()) item->setHoverName(name); spawnAtLocation(item, 0);}
void Minecart::animateHurt(){ setHurtDir(-getHurtDir()); setHurtTime(10); setDamage(getDamage() + (getDamage() * 10));}
bool Minecart::isPickable(){ return !removed;}
void Minecart::remove(){ Entity::remove(); //if (soundUpdater != NULL) soundUpdater->tick();}
void Minecart::tick(){ //if (soundUpdater != NULL) soundUpdater->tick(); // 4J - make minecarts (server-side) tick twice, to put things back to how they were when we were accidently ticking them twice for( int i = 0; i < 2; i++ ) { if (getHurtTime() > 0) setHurtTime(getHurtTime() - 1); if (getDamage() > 0) setDamage(getDamage() - 1); if(y < -64) { outOfWorld(); }
if (!level->isClientSide && dynamic_cast<ServerLevel *>(level) != NULL) { MinecraftServer *server = ((ServerLevel *) level)->getServer(); int waitTime = getPortalWaitTime();
if (isInsidePortal) { if (server->isNetherEnabled()) { if (riding == NULL) { if (portalTime++ >= waitTime) { portalTime = waitTime; changingDimensionDelay = getDimensionChangingDelay();
int targetDimension;
if (level->dimension->id == -1) { targetDimension = 0; } else { targetDimension = -1; }
changeDimension(targetDimension); } } isInsidePortal = false; } } else { if (portalTime > 0) portalTime -= 4; if (portalTime < 0) portalTime = 0; } if (changingDimensionDelay > 0) changingDimensionDelay--; }
// 4J Stu - Fix for #8284 - Gameplay: Collision: Minecart clips into/ through blocks at the end of the track, prevents player from riding if (level->isClientSide) // && lSteps > 0) { if (lSteps > 0) { double xt = x + (lx - x) / lSteps; double yt = y + (ly - y) / lSteps; double zt = z + (lz - z) / lSteps;
double yrd = Mth::wrapDegrees(lyr - yRot);
yRot += (float) ( (yrd) / lSteps ); xRot += (float) ( (lxr - xRot) / lSteps );
lSteps--; setPos(xt, yt, zt); setRot(yRot, xRot); } else { setPos(x, y, z); setRot(yRot, xRot); }
return; // 4J - return here stops the client-side version of this from ticking twice } xo = x; yo = y; zo = z;
yd -= 0.04f;
int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; }
double max = 0.4;
double slideSpeed = 1 / 128.0; int tile = level->getTile(xt, yt, zt); if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); moveAlongTrack(xt, yt, zt, max, slideSpeed, tile, data);
if (tile == Tile::activatorRail_Id) { activateMinecart(xt, yt, zt, (data & BaseRailTile::RAIL_DATA_BIT) != 0); } } else { comeOffTrack(max); }
checkInsideTiles();
xRot = 0; double xDiff = xo - x; double zDiff = zo - z; if (xDiff * xDiff + zDiff * zDiff > 0.001) { yRot = (float) (atan2(zDiff, xDiff) * 180 / PI); if (flipped) yRot += 180; }
double rotDiff = Mth::wrapDegrees(yRot - yRotO);
if (rotDiff < -170 || rotDiff >= 170) { yRot += 180; flipped = !flipped; } setRot(yRot, xRot);
vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f)); if (entities != NULL && !entities->empty()) { AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { shared_ptr<Entity> e = (*it); //entities->at(i); if (e != rider.lock() && e->isPushable() && e->instanceof(eTYPE_MINECART)) { shared_ptr<Minecart> cart = dynamic_pointer_cast<Minecart>(e); cart->m_bHasPushedCartThisTick = false; cart->push(shared_from_this());
// 4J Added - We should only be pushed by one minecart per tick, the closest one // Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn if( cart->m_bHasPushedCartThisTick ) break; } } }
if (rider.lock() != NULL) { if (rider.lock()->removed) { if (rider.lock()->riding == shared_from_this()) { rider.lock()->riding = nullptr; } rider = weak_ptr<Entity>(); } } }}
void Minecart::activateMinecart(int xt, int yt, int zt, bool state){}
void Minecart::comeOffTrack(double maxSpeed){ if (xd < -maxSpeed) xd = -maxSpeed; if (xd > +maxSpeed) xd = +maxSpeed; if (zd < -maxSpeed) zd = -maxSpeed; if (zd > +maxSpeed) zd = +maxSpeed; if (onGround) { xd *= 0.5f; yd *= 0.5f; zd *= 0.5f; } move(xd, yd, zd);
if (!onGround) { xd *= 0.95f; yd *= 0.95f; zd *= 0.95f; }}
void Minecart::moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data){ fallDistance = 0;
Vec3 *oldPos = getPos(x, y, z); y = yt;
bool powerTrack = false; bool haltTrack = false; if (tile == Tile::goldenRail_Id) { powerTrack = (data & BaseRailTile::RAIL_DATA_BIT) != 0; haltTrack = !powerTrack; } if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { data &= BaseRailTile::RAIL_DIRECTION_MASK; }
if (data >= 2 && data <= 5) { y = yt + 1; }
if (data == 2) xd -= slideSpeed; if (data == 3) xd += slideSpeed; if (data == 4) zd += slideSpeed; if (data == 5) zd -= slideSpeed;
int exits[2][3]; memcpy( exits, EXITS[data], sizeof(int) * 2 * 3);
double xD = exits[1][0] - exits[0][0]; double zD = exits[1][2] - exits[0][2]; double dd = sqrt(xD * xD + zD * zD);
double flip = xd * xD + zd * zD; if (flip < 0) { xD = -xD; zD = -zD; }
double pow = sqrt(xd * xd + zd * zd); if (pow > 2) { pow = 2; }
xd = pow * xD / dd; zd = pow * zD / dd;
if ( rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) { shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(rider.lock());
double forward = living->yya;
if (forward > 0) { double riderXd = -sin(living->yRot * PI / 180); double riderZd = cos(living->yRot * PI / 180);
double ownDist = xd * xd + zd * zd;
if (ownDist < 0.01) { xd += riderXd * 0.1; zd += riderZd * 0.1;
haltTrack = false; } } }
// on golden rails without power, stop the cart if (haltTrack) { double speedLength = sqrt(xd * xd + zd * zd); if (speedLength < .03) { xd *= 0; yd *= 0; zd *= 0; } else { xd *= 0.5f; yd *= 0; zd *= 0.5f; } }
double progress = 0; double x0 = xt + 0.5 + exits[0][0] * 0.5; double z0 = zt + 0.5 + exits[0][2] * 0.5; double x1 = xt + 0.5 + exits[1][0] * 0.5; double z1 = zt + 0.5 + exits[1][2] * 0.5;
xD = x1 - x0; zD = z1 - z0;
if (xD == 0) { x = xt + 0.5; progress = z - zt; } else if (zD == 0) { z = zt + 0.5; progress = x - xt; } else {
double xx = x - x0; double zz = z - z0;
progress = (xx * xD + zz * zD) * 2; }
x = x0 + xD * progress; z = z0 + zD * progress;
setPos(x, y + heightOffset, z);
double xdd = xd; double zdd = zd; if (rider.lock() != NULL) { xdd *= 0.75; zdd *= 0.75; } if (xdd < -maxSpeed) xdd = -maxSpeed; if (xdd > +maxSpeed) xdd = +maxSpeed; if (zdd < -maxSpeed) zdd = -maxSpeed; if (zdd > +maxSpeed) zdd = +maxSpeed;
move(xdd, 0, zdd);
if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) { setPos(x, y + exits[0][1], z); } else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) { setPos(x, y + exits[1][1], z); }
applyNaturalSlowdown();
Vec3 *newPos = getPos(x, y, z); if (newPos != NULL && oldPos != NULL) { double speed = (oldPos->y - newPos->y) * 0.05;
pow = sqrt(xd * xd + zd * zd); if (pow > 0) { xd = xd / pow * (pow + speed); zd = zd / pow * (pow + speed); } setPos(x, newPos->y, z); }
int xn = Mth::floor(x); int zn = Mth::floor(z); if (xn != xt || zn != zt) { pow = sqrt(xd * xd + zd * zd);
xd = pow * (xn - xt); zd = pow * (zn - zt); }
// if on golden rail with power, increase speed if (powerTrack) { double speedLength = sqrt(xd * xd + zd * zd); if (speedLength > .01) { double speed = 0.06; xd += xd / speedLength * speed; zd += zd / speedLength * speed; } else { // if the minecart is standing still, accelerate it away from // potential walls if (data == BaseRailTile::DIR_FLAT_X) { if (level->isSolidBlockingTile(xt - 1, yt, zt)) { xd = .02; } else if (level->isSolidBlockingTile(xt + 1, yt, zt)) { xd = -.02; } } else if (data == BaseRailTile::DIR_FLAT_Z) { if (level->isSolidBlockingTile(xt, yt, zt - 1)) { zd = .02; } else if (level->isSolidBlockingTile(xt, yt, zt + 1)) { zd = -.02; } } } }}
void Minecart::applyNaturalSlowdown(){ if (rider.lock() != NULL) { xd *= 0.997f; yd *= 0; zd *= 0.997f; } else { xd *= 0.96f; yd *= 0; zd *= 0.96f; }}
Vec3 *Minecart::getPosOffs(double x, double y, double z, double offs){ int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; }
int tile = level->getTile(xt, yt, zt); if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt);
if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { data &= BaseRailTile::RAIL_DIRECTION_MASK; }
y = yt; if (data >= 2 && data <= 5) { y = yt + 1; }
// 4J TODO Is this a good way to copy the bit of the array that we need? int exits[2][3]; memcpy( &exits, (void *)EXITS[data], sizeof(int) * 2 * 3); //int exits[2][3] = EXITS[data];
double xD = exits[1][0] - exits[0][0]; double zD = exits[1][2] - exits[0][2]; double dd = sqrt(xD * xD + zD * zD); xD /= dd; zD /= dd;
x += xD * offs; z += zD * offs;
if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) { y += exits[0][1]; } else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) { y += exits[1][1]; }
return getPos(x, y, z); } return NULL;}
Vec3 *Minecart::getPos(double x, double y, double z){ int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; }
int tile = level->getTile(xt, yt, zt); if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); y = yt;
if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { data &= BaseRailTile::RAIL_DIRECTION_MASK; }
if (data >= 2 && data <= 5) { y = yt + 1; }
// 4J TODO Is this a good way to copy the bit of the array that we need? int exits[2][3]; memcpy( &exits, (void *)EXITS[data], sizeof(int) * 2 * 3); //int exits[2][3] = EXITS[data];
double progress = 0; double x0 = xt + 0.5 + exits[0][0] * 0.5; double y0 = yt + 0.5 + exits[0][1] * 0.5; double z0 = zt + 0.5 + exits[0][2] * 0.5; double x1 = xt + 0.5 + exits[1][0] * 0.5; double y1 = yt + 0.5 + exits[1][1] * 0.5; double z1 = zt + 0.5 + exits[1][2] * 0.5;
double xD = x1 - x0; double yD = (y1 - y0) * 2; double zD = z1 - z0;
if (xD == 0) { x = xt + 0.5; progress = z - zt; } else if (zD == 0) { z = zt + 0.5; progress = x - xt; } else {
double xx = x - x0; double zz = z - z0;
progress = (xx * xD + zz * zD) * 2; }
x = x0 + xD * progress; y = y0 + yD * progress; z = z0 + zD * progress; if (yD < 0) y += 1; if (yD > 0) y += 0.5; return Vec3::newTemp(x, y, z); } return NULL;}
void Minecart::readAdditionalSaveData(CompoundTag *tag){ if (tag->getBoolean(L"CustomDisplayTile")) { setDisplayTile(tag->getInt(L"DisplayTile")); setDisplayData(tag->getInt(L"DisplayData")); setDisplayOffset(tag->getInt(L"DisplayOffset")); }
if (tag->contains(L"CustomName") && tag->getString(L"CustomName").length() > 0) name = tag->getString(L"CustomName");}
void Minecart::addAdditonalSaveData(CompoundTag *tag){ if (hasCustomDisplay()) { tag->putBoolean(L"CustomDisplayTile", true); tag->putInt(L"DisplayTile", getDisplayTile() == NULL ? 0 : getDisplayTile()->id); tag->putInt(L"DisplayData", getDisplayData()); tag->putInt(L"DisplayOffset", getDisplayOffset()); }
if (!name.empty()) tag->putString(L"CustomName", name);}
float Minecart::getShadowHeightOffs(){ return 0;}
void Minecart::push(shared_ptr<Entity> e){ if (level->isClientSide) return;
if (e == rider.lock()) return; if ( e->instanceof(eTYPE_LIVINGENTITY) && !e->instanceof(eTYPE_PLAYER) && !e->instanceof(eTYPE_VILLAGERGOLEM) && (getType() == TYPE_RIDEABLE) && (xd * xd + zd * zd > 0.01) ) { if ( (rider.lock() == NULL) && (e->riding == NULL) ) { e->ride( shared_from_this() ); } }
double xa = e->x - x; double za = e->z - z;
double dd = xa * xa + za * za; if (dd >= 0.0001f) { dd = sqrt(dd); xa /= dd; za /= dd; double pow = 1 / dd; if (pow > 1) pow = 1; xa *= pow; za *= pow; xa *= 0.1f; za *= 0.1f;
xa *= 1 - pushthrough; za *= 1 - pushthrough; xa *= 0.5; za *= 0.5;
if (e->instanceof(eTYPE_MINECART)) { double xo = e->x - x; double zo = e->z - z;
//4J Stu - Brought forward changes to fix minecarts pushing each other // Fix for #38882 - TU5: Gameplay: Minecart with furnace is not able to move another minecart on the rail. Vec3 *dir = Vec3::newTemp(xo, 0, zo)->normalize(); Vec3 *facing = Vec3::newTemp(cos(yRot * PI / 180), 0, sin(yRot * PI / 180))->normalize();
double dot = abs(dir->dot(facing));
if (dot < 0.8f) { return; }
double xdd = (e->xd + xd); double zdd = (e->zd + zd);
shared_ptr<Minecart> cart = dynamic_pointer_cast<Minecart>(e); if (cart != NULL && cart->getType() == TYPE_FURNACE && getType() != TYPE_FURNACE) { xd *= 0.2f; zd *= 0.2f; push( e->xd - xa, 0, e->zd - za); e->xd *= 0.95f; e->zd *= 0.95f; m_bHasPushedCartThisTick = true; } else if (cart != NULL && cart->getType() != TYPE_FURNACE && getType() == TYPE_FURNACE) { e->xd *= 0.2f; e->zd *= 0.2f; e->push(xd + xa, 0, zd + za); xd *= 0.95f; zd *= 0.95f; m_bHasPushedCartThisTick = true; } else { xdd /= 2; zdd /= 2; xd *= 0.2f; zd *= 0.2f; push(xdd - xa, 0, zdd - za); e->xd *= 0.2f; e->zd *= 0.2f; e->push(xdd + xa, 0, zdd + za); m_bHasPushedCartThisTick = true;
// 4J Stu - Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn // Minecarts can end up stuck inside each other, so if they are too close then they should separate quickly double modifier = 1.0; if( abs(xo) < 1 && abs(zo) < 1) { modifier += 1-( (abs(xo) + abs(zo))/2); } // 4J Stu - Decelerate the cart that is pushing this one if they are too close e->xd /= modifier; e->zd /= modifier;
// 4J Backup fix for QNAN if( !(xd==xd) ) xd = 0; if( !(zd==zd) ) zd = 0; if( !(e->xd == e->xd) ) e->xd = 0; if( !(e->zd == e->zd) ) e->zd = 0; }
} else { push(-xa, 0, -za); e->push(xa / 4, 0, za / 4); } }}
void Minecart::lerpTo(double x, double y, double z, float yRot, float xRot, int steps){ lx = x; ly = y; lz = z; lyr = yRot; lxr = xRot;
lSteps = steps + 2;
xd = lxd; yd = lyd; zd = lzd;}
void Minecart::lerpMotion(double xd, double yd, double zd){ lxd = this->xd = xd; lyd = this->yd = yd; lzd = this->zd = zd;}
void Minecart::setDamage(float damage){ entityData->set(DATA_ID_DAMAGE, damage);}
float Minecart::getDamage(){ return entityData->getFloat(DATA_ID_DAMAGE);}
void Minecart::setHurtTime(int hurtTime){ entityData->set(DATA_ID_HURT, hurtTime);}
int Minecart::getHurtTime(){ return entityData->getInteger(DATA_ID_HURT);}
void Minecart::setHurtDir(int hurtDir){ entityData->set(DATA_ID_HURTDIR, hurtDir);}
int Minecart::getHurtDir(){ return entityData->getInteger(DATA_ID_HURTDIR);}
Tile *Minecart::getDisplayTile(){ if (!hasCustomDisplay()) return getDefaultDisplayTile(); int id = getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) & 0xFFFF; return id > 0 && id < Tile::TILE_NUM_COUNT ? Tile::tiles[id] : NULL;}
Tile *Minecart::getDefaultDisplayTile(){ return NULL;}
int Minecart::getDisplayData(){ if (!hasCustomDisplay()) return getDefaultDisplayData(); return getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) >> 16;}
int Minecart::getDefaultDisplayData(){ return 0;}
int Minecart::getDisplayOffset(){ if (!hasCustomDisplay()) return getDefaultDisplayOffset(); return getEntityData()->getInteger(DATA_ID_DISPLAY_OFFSET);}
int Minecart::getDefaultDisplayOffset(){ return 6;}
void Minecart::setDisplayTile(int id){ getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (getDisplayData() << 16)); setCustomDisplay(true);}
void Minecart::setDisplayData(int data){ Tile *tile = getDisplayTile(); int id = tile == NULL ? 0 : tile->id;
getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (data << 16)); setCustomDisplay(true);}
void Minecart::setDisplayOffset(int offset){ getEntityData()->set(DATA_ID_DISPLAY_OFFSET, offset); setCustomDisplay(true);}
bool Minecart::hasCustomDisplay(){ return getEntityData()->getByte(DATA_ID_CUSTOM_DISPLAY) == 1;}
void Minecart::setCustomDisplay(bool value){ getEntityData()->set(DATA_ID_CUSTOM_DISPLAY, (byte) (value ? 1 : 0));}
void Minecart::setCustomName(const wstring &name){ this->name = name;}
wstring Minecart::getAName(){ if (!name.empty()) return name; return Entity::getAName();}
bool Minecart::hasCustomName(){ return !name.empty();}
wstring Minecart::getCustomName(){ return name;}