aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/EnderMan.cpp
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.World/EnderMan.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.World/EnderMan.cpp')
-rw-r--r--Minecraft.World/EnderMan.cpp411
1 files changed, 411 insertions, 0 deletions
diff --git a/Minecraft.World/EnderMan.cpp b/Minecraft.World/EnderMan.cpp
new file mode 100644
index 00000000..abfc5cb5
--- /dev/null
+++ b/Minecraft.World/EnderMan.cpp
@@ -0,0 +1,411 @@
+#include "stdafx.h"
+#include "net.minecraft.world.entity.player.h"
+#include "net.minecraft.world.entity.h"
+#include "net.minecraft.world.item.h"
+#include "net.minecraft.world.level.h"
+#include "net.minecraft.world.level.tile.h"
+#include "net.minecraft.world.damagesource.h"
+#include "net.minecraft.world.phys.h"
+#include "com.mojang.nbt.h"
+#include "..\Minecraft.Client\Textures.h"
+#include "EnderMan.h"
+
+
+
+bool EnderMan::MAY_TAKE[256];
+
+void EnderMan::staticCtor()
+{
+ ZeroMemory(MAY_TAKE, sizeof(bool) * 256);
+ MAY_TAKE[Tile::grass_Id] = true;
+ MAY_TAKE[Tile::dirt_Id] = true;
+ MAY_TAKE[Tile::sand_Id] = true;
+ MAY_TAKE[Tile::gravel_Id] = true;
+ MAY_TAKE[Tile::flower_Id] = true;
+ MAY_TAKE[Tile::rose_Id] = true;
+ MAY_TAKE[Tile::mushroom1_Id] = true;
+ MAY_TAKE[Tile::mushroom2_Id] = true;
+ MAY_TAKE[Tile::tnt_Id] = true;
+ MAY_TAKE[Tile::cactus_Id] = true;
+ MAY_TAKE[Tile::clay_Id] = true;
+ MAY_TAKE[Tile::pumpkin_Id] = true;
+ MAY_TAKE[Tile::melon_Id] = true;
+ MAY_TAKE[Tile::mycel_Id] = true;
+}
+
+EnderMan::EnderMan(Level *level) : Monster( level )
+{
+ // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
+ // the derived version of the function is called
+ // Brought forward from 1.2.3
+ this->defineSynchedData();
+
+ // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called
+ health = getMaxHealth();
+
+ // 4J initialisors
+ teleportTime = 0;
+ aggroTime = 0;
+
+ this->textureIdx = TN_MOB_ENDERMAN; // 4J was "/mob/enderman.png";
+ runSpeed = 0.2f;
+ attackDamage = 7;
+ setSize(0.6f, 2.9f);
+ footSize = 1;
+}
+
+int EnderMan::getMaxHealth()
+{
+ return 40;
+}
+
+// Brought forward from 1.2.3
+void EnderMan::defineSynchedData()
+{
+ Monster::defineSynchedData();
+
+ entityData->define(DATA_CARRY_ITEM_ID, (byte) 0);
+ entityData->define(DATA_CARRY_ITEM_DATA, (byte) 0);
+ entityData->define(DATA_CREEPY, (byte) 0);
+}
+
+void EnderMan::addAdditonalSaveData(CompoundTag *tag)
+{
+ Monster::addAdditonalSaveData(tag);
+ tag->putShort(L"carried", (short) getCarryingTile());
+ tag->putShort(L"carriedData", (short) getCarryingData());
+}
+
+void EnderMan::readAdditionalSaveData(CompoundTag *tag)
+{
+ Monster::readAdditionalSaveData(tag);
+ setCarryingTile(tag->getShort(L"carried"));
+ setCarryingData(tag->getShort(L"carryingData"));
+}
+
+shared_ptr<Entity> EnderMan::findAttackTarget()
+{
+#ifndef _FINAL_BUILD
+ if(app.GetMobsDontAttackEnabled())
+ {
+ return shared_ptr<Player>();
+ }
+#endif
+
+ shared_ptr<Player> player = level->getNearestAttackablePlayer(shared_from_this(), 64);
+ if (player != NULL)
+ {
+ if (isLookingAtMe(player))
+ {
+ if (aggroTime++ == 5)
+ {
+ aggroTime = 0;
+ setCreepy(true);
+ return player;
+ }
+ }
+ else
+ {
+ aggroTime = 0;
+ }
+ }
+ return nullptr;
+}
+
+bool EnderMan::isLookingAtMe(shared_ptr<Player> player)
+{
+ shared_ptr<ItemInstance> helmet = player->inventory->armor[3];
+ if (helmet != NULL && helmet->id == Tile::pumpkin_Id) return false;
+
+ Vec3 *look = player->getViewVector(1)->normalize();
+ Vec3 *dir = Vec3::newTemp(x - player->x, (bb->y0 + bbHeight / 2) - (player->y + player->getHeadHeight()), z - player->z);
+ double dist = dir->length();
+ dir = dir->normalize();
+ double dot = look->dot(dir);
+ if (dot > 1 - 0.025 / dist)
+ {
+ return player->canSee(shared_from_this());
+ }
+ return false;
+}
+
+void EnderMan::aiStep()
+{
+ if (this->isInWaterOrRain()) hurt(DamageSource::drown, 1);
+
+ runSpeed = attackTarget != NULL ? 6.5f : 0.3f;
+
+ if (!level->isClientSide)
+ {
+ if (getCarryingTile() == 0)
+ {
+ if (random->nextInt(20) == 0)
+ {
+ int xt = Mth::floor(x - 2 + random->nextDouble() * 4);
+ int yt = Mth::floor(y + random->nextDouble() * 3);
+ int zt = Mth::floor(z - 2 + random->nextDouble() * 4);
+ int t = level->getTile(xt, yt, zt);
+ //if (t > 0 && Tile::tiles[t]->isCubeShaped())
+ if(EnderMan::MAY_TAKE[t]) // 4J - Brought forward from 1.2.3
+ {
+ setCarryingTile(level->getTile(xt, yt, zt));
+ setCarryingData(level->getData(xt, yt, zt));
+ level->setTile(xt, yt, zt, 0);
+ }
+ }
+ }
+ else
+ {
+ if (random->nextInt(2000) == 0)
+ {
+ int xt = Mth::floor(x - 1 + random->nextDouble() * 2);
+ int yt = Mth::floor(y + random->nextDouble() * 2);
+ int zt = Mth::floor(z - 1 + random->nextDouble() * 2);
+ int t = level->getTile(xt, yt, zt);
+ int bt = level->getTile(xt, yt - 1, zt);
+ if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped())
+ {
+ level->setTileAndData(xt, yt, zt, getCarryingTile(), getCarryingData());
+ setCarryingTile(0);
+ }
+ }
+ }
+ }
+
+ // 4J - Brought forward particles from 1.2.3
+ for (int i = 0; i < 2; i++)
+ {
+ level->addParticle(eParticleType_ender, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight - 0.25f, z + (random->nextDouble() - 0.5) * bbWidth,
+ (random->nextDouble() - 0.5) * 2, -random->nextDouble(), (random->nextDouble() - 0.5) * 2);
+ }
+
+ if (level->isDay() && !level->isClientSide)
+ {
+ float br = getBrightness(1);
+ if (br > 0.5f)
+ {
+ if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2)
+ {
+ // 4J - Brought forward behaviour change from 1.2.3
+ //onFire = 20 * 15;
+ attackTarget = nullptr;
+ setCreepy(false);
+ teleport();
+ }
+ }
+ }
+ // 4J Brought forward behaviour change from 1.2.3
+ if (isInWaterOrRain() || isOnFire())
+ {
+ attackTarget = nullptr;
+ setCreepy(false);
+ teleport();
+ }
+ jumping = false;
+ if (attackTarget != NULL)
+ {
+ this->lookAt(attackTarget, 100, 100);
+ }
+
+ if (!level->isClientSide && isAlive())
+ {
+ if (attackTarget != NULL)
+ {
+ if ( dynamic_pointer_cast<Player>(attackTarget) != NULL && isLookingAtMe(dynamic_pointer_cast<Player>(attackTarget)))
+ {
+ xxa = yya = 0;
+ runSpeed = 0;
+ if (attackTarget->distanceToSqr(shared_from_this()) < 4 * 4)
+ {
+ teleport();
+ }
+ teleportTime = 0;
+ }
+ else if (attackTarget->distanceToSqr(shared_from_this()) > 16 * 16)
+ {
+ if (teleportTime++ >= 30)
+ {
+ if (teleportTowards(attackTarget))
+ {
+ teleportTime = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ setCreepy(false);
+ teleportTime = 0;
+ }
+ }
+
+ Monster::aiStep();
+}
+
+bool EnderMan::teleport()
+{
+ double xx = x + (random->nextDouble() - 0.5) * 64;
+ double yy = y + (random->nextInt(64) - 32);
+ double zz = z + (random->nextDouble() - 0.5) * 64;
+ return teleport(xx, yy, zz);
+}
+
+bool EnderMan::teleportTowards(shared_ptr<Entity> e)
+{
+ Vec3 *dir = Vec3::newTemp(x - e->x, bb->y0 + bbHeight / 2 - e->y + e->getHeadHeight(), z - e->z);
+ dir = dir->normalize();
+ double d = 16;
+ double xx = x + (random->nextDouble() - 0.5) * 8 - dir->x * d;
+ double yy = y + (random->nextInt(16) - 8) - dir->y * d;
+ double zz = z + (random->nextDouble() - 0.5) * 8 - dir->z * d;
+ return teleport(xx, yy, zz);
+}
+
+bool EnderMan::teleport(double xx, double yy, double zz)
+{
+ double xo = x;
+ double yo = y;
+ double zo = z;
+
+ x = xx;
+ y = yy;
+ z = zz;
+ bool ok = false;
+ int xt = Mth::floor(x);
+ int yt = Mth::floor(y);
+ int zt = Mth::floor(z);
+
+ if (level->hasChunkAt(xt, yt, zt))
+ {
+ bool landed = false;
+ while (!landed && yt > 0)
+ {
+ int t = level->getTile(xt, yt - 1, zt);
+ if (t == 0 || !(Tile::tiles[t]->material->blocksMotion()))
+ {
+ y--;
+ yt--;
+ }
+ else
+ {
+ landed = true;
+ }
+ }
+ if (landed)
+ {
+ setPos(x, y, z);
+ if (level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid(bb))
+ {
+ ok = true;
+ }
+ }
+ }
+
+
+ if (ok)
+ {
+ int count = 128;
+ for (int i = 0; i < count; i++)
+ {
+ double d = i / (count - 1.0);
+ float xa = (random->nextFloat() - 0.5f) * 0.2f;
+ float ya = (random->nextFloat() - 0.5f) * 0.2f;
+ float za = (random->nextFloat() - 0.5f) * 0.2f;
+
+ double _x = xo + (x - xo) * d + (random->nextDouble() - 0.5) * bbWidth * 2;
+ double _y = yo + (y - yo) * d + random->nextDouble() * bbHeight;
+ double _z = zo + (z - zo) * d + (random->nextDouble() - 0.5) * bbWidth * 2;
+
+ // 4J - Brought forward particle change from 1.2.3
+ //level->addParticle(eParticleType_largesmoke, _x, _y, _z, xa, ya, za);
+ level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za);
+ }
+ // 4J - moved sounds forward from 1.2.3
+ level->playSound(xo, yo, zo, eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
+ level->playSound(shared_from_this(), eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
+ return true;
+ }
+ else
+ {
+ setPos(xo, yo, zo);
+ return false;
+ }
+}
+
+int EnderMan::getAmbientSound()
+{
+ // 4J - brought sound change forward from 1.2.3
+ return eSoundType_MOB_ENDERMEN_IDLE;
+}
+
+int EnderMan::getHurtSound()
+{
+ // 4J - brought sound change forward from 1.2.3
+ return eSoundType_MOB_ENDERMEN_HIT;
+}
+
+int EnderMan::getDeathSound()
+{
+ // 4J - brought sound change forward from 1.2.3
+ return eSoundType_MOB_ENDERMEN_DEATH;
+}
+
+int EnderMan::getDeathLoot()
+{
+ return Item::enderPearl_Id;
+}
+
+void EnderMan::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
+{
+ int loot = getDeathLoot();
+ if (loot > 0)
+ {
+ int count = random->nextInt(2 + playerBonusLevel);
+ for (int i = 0; i < count; i++)
+ spawnAtLocation(loot, 1);
+ }
+}
+
+// 4J Brought forward from 1.2.3 to help fix Enderman behaviour
+void EnderMan::setCarryingTile(int carryingTile)
+{
+ entityData->set(DATA_CARRY_ITEM_ID, (byte) (carryingTile & 0xff));
+}
+
+int EnderMan::getCarryingTile()
+{
+ return entityData->getByte(DATA_CARRY_ITEM_ID);
+}
+
+void EnderMan::setCarryingData(int carryingData)
+{
+ entityData->set(DATA_CARRY_ITEM_DATA, (byte) (carryingData & 0xff));
+}
+
+int EnderMan::getCarryingData()
+{
+ return entityData->getByte(DATA_CARRY_ITEM_DATA);
+}
+
+bool EnderMan::hurt(DamageSource *source, int damage)
+{
+ if (dynamic_cast<IndirectEntityDamageSource *>(source) != NULL)
+ {
+ for (int i = 0; i < 64; i++)
+ {
+ if (teleport()) return true;
+ }
+ return false;
+ }
+ return Monster::hurt(source, damage);
+}
+
+bool EnderMan::isCreepy()
+{
+ return entityData->getByte(DATA_CREEPY) > 0;
+}
+
+void EnderMan::setCreepy(bool creepy)
+{
+ entityData->set(DATA_CREEPY, (byte)(creepy ? 1 : 0));
+} \ No newline at end of file