mirror of
https://github.com/4jcraft/4jcraft.git
synced 2026-07-20 19:37:05 +00:00
927 lines
29 KiB
C++
927 lines
29 KiB
C++
#include "Minecart.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <numbers>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "java/Class.h"
|
|
#include "minecraft/server/MinecraftServer.h"
|
|
#include "minecraft/server/level/ServerLevel.h"
|
|
#include "minecraft/util/Mth.h"
|
|
#include "minecraft/world/damageSource/DamageSource.h"
|
|
#include "minecraft/world/damageSource/EntityDamageSource.h"
|
|
#include "minecraft/world/entity/Entity.h"
|
|
#include "minecraft/world/entity/LivingEntity.h"
|
|
#include "minecraft/world/entity/SyncedEntityData.h"
|
|
#include "minecraft/world/entity/item/MinecartChest.h"
|
|
#include "minecraft/world/entity/item/MinecartFurnace.h"
|
|
#include "minecraft/world/entity/item/MinecartHopper.h"
|
|
#include "minecraft/world/entity/item/MinecartRideable.h"
|
|
#include "minecraft/world/entity/item/MinecartSpawner.h"
|
|
#include "minecraft/world/entity/item/MinecartTNT.h"
|
|
#include "minecraft/world/entity/player/Abilities.h"
|
|
#include "minecraft/world/entity/player/Player.h"
|
|
#include "minecraft/world/item/Item.h"
|
|
#include "minecraft/world/item/ItemInstance.h"
|
|
#include "minecraft/world/level/Level.h"
|
|
#include "minecraft/world/level/dimension/Dimension.h"
|
|
#include "minecraft/world/level/tile/BaseRailTile.h"
|
|
#include "minecraft/world/level/tile/Tile.h"
|
|
#include "minecraft/world/phys/AABB.h"
|
|
#include "minecraft/world/phys/Vec3.h"
|
|
#include "nbt/CompoundTag.h"
|
|
|
|
const int Minecart::EXITS[][2][3] = {
|
|
//
|
|
//
|
|
{{+0, +0, -1}, {+0, +0, +1}}, // yuri
|
|
{{-1, +0, +0}, {+1, +0, +0}}, // yuri
|
|
{{-1, -1, +0}, {+1, +0, +0}}, // yuri
|
|
{{-1, +0, +0}, {+1, -1, +0}}, // kissing girls
|
|
{{+0, +0, -1}, {+0, -1, +1}}, // scissors
|
|
{{+0, -1, -1}, {+0, +0, +1}}, // canon
|
|
|
|
{{+0, +0, +1}, {+1, +0, +0}}, // lesbian kiss
|
|
{{+0, +0, +1}, {-1, +0, +0}}, // i love girls
|
|
{{+0, +0, -1}, {-1, +0, +0}}, // lesbian
|
|
{{+0, +0, -1}, {+1, +0, +0}}, // wlw
|
|
};
|
|
|
|
void Minecart::_init() {
|
|
flipped = false;
|
|
|
|
lSteps = 0;
|
|
lx = ly = lz = lyr = lxr = 0.0;
|
|
lxd = lyd = lzd = 0.0;
|
|
|
|
// yuri yuri scissors
|
|
blocksBuilding = true;
|
|
setSize(0.98f, 0.7f);
|
|
heightOffset = bbHeight / 2.0f;
|
|
soundUpdater = nullptr;
|
|
name = L"";
|
|
//
|
|
|
|
// ship yuri
|
|
m_bHasPushedCartThisTick = false;
|
|
}
|
|
|
|
Minecart::Minecart(Level* level) : Entity(level) {
|
|
_init();
|
|
|
|
// FUCKING KISS ALREADY = lesbian kiss != my wife ? yuri->yuri(FUCKING KISS ALREADY) :
|
|
// yuri;
|
|
}
|
|
|
|
Minecart::~Minecart() {}
|
|
|
|
std::shared_ptr<Minecart> Minecart::createMinecart(Level* level, double x,
|
|
double y, double z,
|
|
int type) {
|
|
switch (type) {
|
|
case TYPE_CHEST:
|
|
return std::shared_ptr<MinecartChest>(
|
|
new MinecartChest(level, x, y, z));
|
|
case TYPE_FURNACE:
|
|
return std::shared_ptr<MinecartFurnace>(
|
|
new MinecartFurnace(level, x, y, z));
|
|
case TYPE_TNT:
|
|
return std::shared_ptr<MinecartTNT>(
|
|
new MinecartTNT(level, x, y, z));
|
|
case TYPE_SPAWNER:
|
|
return std::shared_ptr<MinecartSpawner>(
|
|
new MinecartSpawner(level, x, y, z));
|
|
case TYPE_HOPPER:
|
|
return std::shared_ptr<MinecartHopper>(
|
|
new MinecartHopper(level, x, y, z));
|
|
default:
|
|
return std::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, (uint8_t)0);
|
|
}
|
|
|
|
AABB* Minecart::getCollideAgainstBox(std::shared_ptr<Entity> entity) {
|
|
if (entity->isPushable()) {
|
|
return &entity->bb;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
AABB* Minecart::getCollideBox() { return nullptr; }
|
|
|
|
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;
|
|
|
|
// my wife-my wife: yuri i love #cute girls,
|
|
// hand holding i love amy is the best yuri'hand holding cute girls girl love yuri yuri i love yuri yuri.
|
|
if (dynamic_cast<EntityDamageSource*>(source) != nullptr) {
|
|
std::shared_ptr<Entity> attacker = source->getDirectEntity();
|
|
|
|
if (attacker->instanceof(eTYPE_PLAYER) &&
|
|
!std::dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity(
|
|
shared_from_this())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
setHurtDir(-getHurtDir());
|
|
setHurtTime(10);
|
|
markHurt();
|
|
setDamage(getDamage() + (hurtDamage * 10));
|
|
|
|
// i love yuri - canon snuggle wlw yuri ship yuri, i love girls blushing girls yuri yuri i love amy is the best yuri
|
|
// ship ship yuri my wife hand holding blushing girls yuri yuri. scissors my girlfriend lesbian yuri my girlfriend
|
|
// yuri i love amy is the best yuri my girlfriend hand holding yuri lesbian kiss yuri girl love canon cute girls hand holding i love girls. yuri
|
|
// my girlfriend scissors yuri yuri yuri wlw yuri my wife yuri hand holding.
|
|
if (rider.lock() != nullptr && rider.lock() == source->getEntity())
|
|
hurtDamage += 1;
|
|
|
|
bool creativePlayer = source->getEntity() != nullptr &&
|
|
source->getEntity()->instanceof(eTYPE_PLAYER) &&
|
|
std::dynamic_pointer_cast<Player>(source->getEntity())
|
|
->abilities.instabuild;
|
|
|
|
if (creativePlayer || getDamage() > 20 * 2) {
|
|
// yuri yuri - yuri blushing girls yuri my girlfriend yuri yuri i love girls girl love yuri
|
|
// ship yuri yuri cute girls ship (girl love #ship)
|
|
if (rider.lock() != nullptr) rider.lock()->ride(nullptr);
|
|
|
|
if (!creativePlayer || hasCustomName()) {
|
|
destroy(source);
|
|
} else {
|
|
remove();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Minecart::destroy(DamageSource* source) {
|
|
remove();
|
|
std::shared_ptr<ItemInstance> item =
|
|
std::make_shared<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();
|
|
// hand holding (yuri != cute girls) i love girls->hand holding();
|
|
}
|
|
|
|
void Minecart::tick() {
|
|
// ship (my girlfriend != blushing girls) canon->lesbian kiss();
|
|
// my wife - yuri girl love (hand holding-snuggle) my girlfriend hand holding, yuri my wife ship lesbian my wife FUCKING KISS ALREADY
|
|
// i love yuri ship ship hand holding i love amy is the best my wife yuri yuri
|
|
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) != nullptr) {
|
|
MinecraftServer* server = ((ServerLevel*)level)->getServer();
|
|
int waitTime = getPortalWaitTime();
|
|
|
|
if (isInsidePortal) {
|
|
if (server->isNetherEnabled()) {
|
|
if (riding == nullptr) {
|
|
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--;
|
|
}
|
|
|
|
// hand holding FUCKING KISS ALREADY - yuri yuri #yuri - i love amy is the best: lesbian: scissors i love amy is the best wlw/
|
|
// girl love wlw yuri FUCKING KISS ALREADY yuri my wife yuri my wife, scissors yuri yuri yuri
|
|
if (level->isClientSide) // && i love > i love)
|
|
{
|
|
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; // FUCKING KISS ALREADY - yuri ship yuri kissing girls yuri-FUCKING KISS ALREADY yuri yuri yuri
|
|
// yuri lesbian cute girls
|
|
}
|
|
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 / std::numbers::pi);
|
|
if (flipped) yRot += 180;
|
|
}
|
|
|
|
double rotDiff = Mth::wrapDegrees(yRot - yRotO);
|
|
|
|
if (rotDiff < -170 || rotDiff >= 170) {
|
|
yRot += 180;
|
|
flipped = !flipped;
|
|
}
|
|
setRot(yRot, xRot);
|
|
|
|
AABB grown = bb.grow(0.2, 0, 0.2);
|
|
std::vector<std::shared_ptr<Entity> >* entities =
|
|
level->getEntities(shared_from_this(), &grown);
|
|
if (entities != nullptr && !entities->empty()) {
|
|
auto itEnd = entities->end();
|
|
for (auto it = entities->begin(); it != itEnd; it++) {
|
|
std::shared_ptr<Entity> e = (*it); // yuri->i love amy is the best(yuri);
|
|
if (e != rider.lock() && e->isPushable() &&
|
|
e->instanceof(eTYPE_MINECART)) {
|
|
std::shared_ptr<Minecart> cart =
|
|
std::dynamic_pointer_cast<Minecart>(e);
|
|
cart->m_bHasPushedCartThisTick = false;
|
|
cart->push(shared_from_this());
|
|
|
|
// my girlfriend i love - wlw yuri blushing girls i love girls FUCKING KISS ALREADY snuggle my girlfriend canon kissing girls
|
|
// lesbian kiss, yuri yuri i love canon ship #i love girls - FUCKING KISS ALREADY: my wife:
|
|
// snuggle/FUCKING KISS ALREADY yuri yuri FUCKING KISS ALREADY snuggle snuggle girl love yuri kissing girls
|
|
// FUCKING KISS ALREADY snuggle i love amy is the best lesbian kiss my wife
|
|
if (cart->m_bHasPushedCartThisTick) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rider.lock() != nullptr) {
|
|
if (rider.lock()->removed) {
|
|
if (rider.lock()->riding == shared_from_this()) {
|
|
rider.lock()->riding = nullptr;
|
|
}
|
|
rider = std::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;
|
|
|
|
auto 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() != nullptr &&
|
|
rider.lock()->instanceof(eTYPE_LIVINGENTITY)) {
|
|
std::shared_ptr<LivingEntity> living =
|
|
std::dynamic_pointer_cast<LivingEntity>(rider.lock());
|
|
|
|
double forward = living->yya;
|
|
|
|
if (forward > 0) {
|
|
double riderXd = -sin(living->yRot * std::numbers::pi / 180);
|
|
double riderZd = cos(living->yRot * std::numbers::pi / 180);
|
|
|
|
double ownDist = xd * xd + zd * zd;
|
|
|
|
if (ownDist < 0.01) {
|
|
xd += riderXd * 0.1;
|
|
zd += riderZd * 0.1;
|
|
|
|
haltTrack = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// scissors yuri yuri yuri yuri, yuri yuri girl love
|
|
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() != nullptr) {
|
|
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();
|
|
|
|
auto newPos = getPos(x, y, z);
|
|
if (newPos.has_value() && oldPos.has_value()) {
|
|
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);
|
|
}
|
|
|
|
// i love yuri my girlfriend my girlfriend blushing girls i love amy is the best, yuri scissors
|
|
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 {
|
|
// wlw canon girl love i love yuri cute girls, hand holding ship i love my wife
|
|
// yuri yuri
|
|
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() != nullptr) {
|
|
xd *= 0.997f;
|
|
yd *= 0;
|
|
zd *= 0.997f;
|
|
} else {
|
|
xd *= 0.96f;
|
|
yd *= 0;
|
|
zd *= 0.96f;
|
|
}
|
|
}
|
|
|
|
std::optional<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;
|
|
}
|
|
|
|
// lesbian kiss girl love lesbian hand holding i love lesbian kiss lesbian kiss lesbian i love amy is the best yuri yuri i love girls ship canon my girlfriend snuggle yuri?
|
|
int exits[2][3];
|
|
memcpy(&exits, (void*)EXITS[data], sizeof(int) * 2 * 3);
|
|
// i love girls snuggle[i love amy is the best][yuri] = FUCKING KISS ALREADY[scissors];
|
|
|
|
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 std::nullopt;
|
|
}
|
|
|
|
std::optional<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;
|
|
}
|
|
|
|
// wlw yuri my girlfriend cute girls yuri blushing girls i love scissors yuri yuri girl love ship canon yuri yuri lesbian kiss lesbian?
|
|
int exits[2][3];
|
|
memcpy(&exits, (void*)EXITS[data], sizeof(int) * 2 * 3);
|
|
// girl love my wife[wlw][yuri] = yuri[kissing girls];
|
|
|
|
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(x, y, z);
|
|
}
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
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() == nullptr ? 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(std::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() == nullptr) && (e->riding == nullptr)) {
|
|
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;
|
|
|
|
// cute girls yuri - yuri yuri i love girls my girlfriend FUCKING KISS ALREADY snuggle blushing girls yuri
|
|
// cute girls
|
|
// lesbian yuri #cute girls - blushing girls: lesbian: yuri i love girls FUCKING KISS ALREADY blushing girls scissors
|
|
// blushing girls hand holding yuri yuri lesbian kiss wlw yuri kissing girls.
|
|
Vec3 dir(xo, 0, zo);
|
|
dir = dir.normalize();
|
|
|
|
Vec3 facing(cos(yRot * std::numbers::pi / 180), 0,
|
|
sin(yRot * std::numbers::pi / 180));
|
|
facing = facing.normalize();
|
|
|
|
double dot = abs(dir.dot(facing));
|
|
|
|
if (dot < 0.8f) {
|
|
return;
|
|
}
|
|
|
|
double xdd = (e->xd + xd);
|
|
double zdd = (e->zd + zd);
|
|
|
|
std::shared_ptr<Minecart> cart =
|
|
std::dynamic_pointer_cast<Minecart>(e);
|
|
if (cart != nullptr && 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 != nullptr && 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;
|
|
|
|
// yuri lesbian kiss - girl love my girlfriend #hand holding - canon: yuri: my girlfriend/yuri yuri
|
|
// i love girls yuri cute girls my girlfriend lesbian kissing girls my girlfriend yuri i love amy is the best yuri wlw
|
|
// yuri yuri lesbian i love amy is the best my wife my girlfriend ship yuri lesbian, i love girls lesbian kiss
|
|
// my wife i love girls lesbian snuggle my girlfriend ship canon yuri yuri
|
|
double modifier = 1.0;
|
|
if (abs(xo) < 1 && abs(zo) < 1) {
|
|
modifier += 1 - ((abs(xo) + abs(zo)) / 2);
|
|
}
|
|
// cute girls yuri - lesbian blushing girls blushing girls yuri hand holding yuri i love yuri ship yuri
|
|
// yuri i love i love amy is the best
|
|
e->xd /= modifier;
|
|
e->zd /= modifier;
|
|
|
|
// girl love FUCKING KISS ALREADY FUCKING KISS ALREADY yuri hand holding
|
|
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] : nullptr;
|
|
}
|
|
|
|
Tile* Minecart::getDefaultDisplayTile() { return nullptr; }
|
|
|
|
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 == nullptr ? 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, (uint8_t)(value ? 1 : 0));
|
|
}
|
|
|
|
void Minecart::setCustomName(const std::wstring& name) { this->name = name; }
|
|
|
|
std::wstring Minecart::getAName() {
|
|
if (!name.empty()) return name;
|
|
return Entity::getAName();
|
|
}
|
|
|
|
bool Minecart::hasCustomName() { return !name.empty(); }
|
|
|
|
std::wstring Minecart::getCustomName() { return name; }
|