diff --git a/Minecraft.Client/CMakeLists.txt b/Minecraft.Client/CMakeLists.txt index 9f75efd2..43812c51 100644 --- a/Minecraft.Client/CMakeLists.txt +++ b/Minecraft.Client/CMakeLists.txt @@ -23,7 +23,7 @@ set(MINECRAFT_CLIENT_SOURCES ${SOURCES_COMMON} ) -add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES}) +add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES} "PhantomModel.h" "PhantomModel.cpp" "PhantomRenderer.h" "PhantomRenderer.cpp") # Only define executable on windows if(PLATFORM_NAME STREQUAL "Windows64") diff --git a/Minecraft.Client/Common/Audio/SoundNames.cpp b/Minecraft.Client/Common/Audio/SoundNames.cpp index a70fa8f9..d2659b3c 100644 --- a/Minecraft.Client/Common/Audio/SoundNames.cpp +++ b/Minecraft.Client/Common/Audio/SoundNames.cpp @@ -229,7 +229,13 @@ const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]= L"mob.rabbit.bunnymurder", L"mob.rabbit.hop", - + + L"mob.phantom.bite", // eSoundType_MOB_PHANTOM_BITE + L"mob.phantom.death", // eSoundType_MOB_PHANTOM_DEATH + L"mob.phantom.flap", // eSoundType_MOB_PHANTOM_FLAP + L"mob.phantom.hurt", // eSoundType_MOB_PHANTOM_HURT + L"mob.phantom.idle", // eSoundType_MOB_PHANTOM_IDLE + L"mob.phantom.swoop", // eSoundType_MOB_PHANTOM_SWOOP }; diff --git a/Minecraft.Client/Common/res/1_2_2/mob/phantom.png b/Minecraft.Client/Common/res/1_2_2/mob/phantom.png new file mode 100644 index 00000000..bacac6e9 Binary files /dev/null and b/Minecraft.Client/Common/res/1_2_2/mob/phantom.png differ diff --git a/Minecraft.Client/Common/res/1_2_2/mob/phantom_eyes.png b/Minecraft.Client/Common/res/1_2_2/mob/phantom_eyes.png new file mode 100644 index 00000000..4fa35bd6 Binary files /dev/null and b/Minecraft.Client/Common/res/1_2_2/mob/phantom_eyes.png differ diff --git a/Minecraft.Client/EntityRenderDispatcher.cpp b/Minecraft.Client/EntityRenderDispatcher.cpp index c0926246..a591756d 100644 --- a/Minecraft.Client/EntityRenderDispatcher.cpp +++ b/Minecraft.Client/EntityRenderDispatcher.cpp @@ -82,6 +82,7 @@ #include "BatRenderer.h" #include "CaveSpiderRenderer.h" #include "RabbitRenderer.h" +#include "PhantomRenderer.h" #include "ArmorStandRenderer.h" #include "EndermiteRenderer.h" #include "MobRenderer.h" @@ -136,6 +137,7 @@ EntityRenderDispatcher::EntityRenderDispatcher() renderers[eTYPE_WITHERBOSS] = new WitherBossRenderer(); renderers[eTYPE_RABBIT] = new RabbitRenderer(); + renderers[eTYPE_PHANTOM] = new PhantomRenderer(); renderers[eTYPE_ENTITY] = new DefaultRenderer(); renderers[eTYPE_PAINTING] = new PaintingRenderer(); diff --git a/Minecraft.Client/PhantomModel.cpp b/Minecraft.Client/PhantomModel.cpp new file mode 100644 index 00000000..7665147f --- /dev/null +++ b/Minecraft.Client/PhantomModel.cpp @@ -0,0 +1,134 @@ +#include "stdafx.h" +#include "..\Minecraft.World\net.minecraft.world.entity.monster.h" +#include "PhantomModel.h" +#include "ModelPart.h" +#include "../Minecraft.World/Phantom.h" + +PhantomModel::PhantomModel() : Model() +{ + texWidth = 64; + texHeight = 64; + + + body = new ModelPart(this, 0, 8); + body->addBox(-3.0f, -2.0f, -8.0f, 5, 3, 9); + + + head = new ModelPart(this, 0, 0); + head->addBox(-4.0f, -2.0f, -5.0f, 7, 3, 5); + + + leftWing = new ModelPart(this, 23, 12); + leftWing->addBox(0.0f, 0.0f, 0.0f, 6, 2, 9); + + + leftWingTip = new ModelPart(this, 16, 24); + leftWingTip->addBox(0.0f, 0.0f, 0.0f, 13, 1, 9); + + + rightWing = new ModelPart(this, 23, 12); + rightWing->bMirror = true; + rightWing->addBox(-6.0f, 0.0f, 0.0f, 6, 2, 9); + + + rightWingTip = new ModelPart(this, 16, 24); + rightWingTip->bMirror = true; + rightWingTip->addBox(-13.0f, 0.0f, 0.0f, 13, 1, 9); + + + tailBase = new ModelPart(this, 3, 20); + tailBase->addBox(-2.0f, 0.0f, 0.0f, 3, 2, 6); + + + tailTip = new ModelPart(this, 4, 29); + tailTip->addBox(-1.0f, 0.0f, 0.0f, 1, 1, 6); + + + body->addChild(head); + body->addChild(leftWing); + body->addChild(rightWing); + body->addChild(tailBase); + leftWing->addChild(leftWingTip); + rightWing->addChild(rightWingTip); + tailBase->addChild(tailTip); + + + const float s = 1.0f / 16.0f; + body->compile(s); + head->compile(s); + leftWing->compile(s); + rightWing->compile(s); + leftWingTip->compile(s); + rightWingTip->compile(s); + tailBase->compile(s); + tailTip->compile(s); +} + +int PhantomModel::modelVersion() +{ + return 3; +} + +void PhantomModel::render(shared_ptr entity, + float time, float r, float bob, + float yRot, float xRot, + float scale, bool usecompiled) +{ + shared_ptr phantom = dynamic_pointer_cast(entity); + if (!phantom) return; + + + float flapTime = (float)phantom->tickCount; + + + const float rad = (float)(PI / 180.0); + float f = flapTime * 7.448451f * rad; + + + body->xRot = -0.1f; + body->yRot = 0.0f; + body->zRot = 0.0f; + body->setPos(0.0f, 0.0f, 0.0f); + + + head->xRot = 0.2f; + head->yRot = 0.0f; + head->zRot = 0.0f; + head->setPos(0.0f, 1.0f, -7.0f); + + + leftWing->setPos(2.0f, -2.0f, -8.0f); + leftWing->xRot = 0.0f; + leftWing->yRot = 0.0f; + leftWing->zRot = 0.1f; + + rightWing->setPos(-3.0f, -2.0f, -8.0f); + rightWing->xRot = 0.0f; + rightWing->yRot = 0.0f; + rightWing->zRot = -0.1f; + + leftWingTip->setPos(6.0f, 0.0f, 0.0f); + leftWingTip->zRot = 0.1f; + + rightWingTip->setPos(-6.0f, 0.0f, 0.0f); + rightWingTip->zRot = -0.1f; + + + tailBase->setPos(0.0f, -2.0f, 1.0f); + tailTip->setPos(0.0f, 0.5f, 6.0f); + + + float flapAngle = cos(f) * 16.0f * rad; + leftWing->zRot += flapAngle; + leftWingTip->zRot += flapAngle; + rightWing->zRot -= flapAngle; + rightWingTip->zRot -= flapAngle; + + + float tailAngle = -(5.0f + cos(f * 2.0f) * 5.0f) * rad; + tailBase->xRot = tailAngle; + tailTip->xRot = tailAngle; + + + body->render(scale, usecompiled); +} \ No newline at end of file diff --git a/Minecraft.Client/PhantomModel.h b/Minecraft.Client/PhantomModel.h new file mode 100644 index 00000000..34afc7b7 --- /dev/null +++ b/Minecraft.Client/PhantomModel.h @@ -0,0 +1,23 @@ +#pragma once +#include "Model.h" + +class PhantomModel : public Model +{ +private: + ModelPart *body; + ModelPart *head; + ModelPart *leftWing; + ModelPart *leftWingTip; + ModelPart *rightWing; + ModelPart *rightWingTip; + ModelPart *tailBase; + ModelPart *tailTip; + +public: + PhantomModel(); + int modelVersion(); + virtual void render(shared_ptr entity, + float time, float r, float bob, + float yRot, float xRot, + float scale, bool usecompiled); +}; diff --git a/Minecraft.Client/PhantomRenderer.cpp b/Minecraft.Client/PhantomRenderer.cpp new file mode 100644 index 00000000..0cf7bc82 --- /dev/null +++ b/Minecraft.Client/PhantomRenderer.cpp @@ -0,0 +1,108 @@ +#include "stdafx.h" +#include "..\Minecraft.World\net.minecraft.world.entity.monster.h" +#include "PhantomRenderer.h" +#include "PhantomModel.h" +#include "../Minecraft.World/Phantom.h" +#include "Textures.h" + + + +ResourceLocation PhantomRenderer::PHANTOM_LOCATION = ResourceLocation(TN_MOB_PHANTOM); +ResourceLocation PhantomRenderer::PHANTOM_EYES_LOCATION = ResourceLocation(TN_MOB_PHANTOM_EYES); + +PhantomRenderer::PhantomRenderer() : MobRenderer(new PhantomModel(), 0.5f) +{ + modelVersion = static_cast(model)->modelVersion(); + this->setArmor(model); +} + +void PhantomRenderer::render(shared_ptr _mob, + double x, double y, double z, + float rot, float a) +{ + + int currentVersion = static_cast(model)->modelVersion(); + if (currentVersion != modelVersion) + { + modelVersion = currentVersion; + model = new PhantomModel(); + this->setArmor(model); + } + + MobRenderer::render(_mob, x, y, z, rot, a); +} + +ResourceLocation *PhantomRenderer::getTextureLocation(shared_ptr mob) +{ + return &PHANTOM_LOCATION; +} + +void PhantomRenderer::scale(shared_ptr mob, float a) +{ + + shared_ptr phantom = dynamic_pointer_cast(mob); + if (phantom) + { + float s = 1.0f + 0.15f * phantom->getPhantomSize(); + glScalef(s, s, s); + } + + //glScalef(0.35f, 0.35f, 0.35f); +} + +void PhantomRenderer::setupPosition(shared_ptr mob, + double x, double y, double z) +{ + MobRenderer::setupPosition(mob, x, y-0.5, z ); +} + +void PhantomRenderer::setupRotations(shared_ptr _mob, + float bob, float bodyRot, float a) +{ + glTranslatef(0.0f, -0.5f, 0.0f); + glTranslatef(0.0f, cos(bob * 0.3f) * 0.1f, 0.0f); + MobRenderer::setupRotations(_mob, bob, bodyRot, a); +} +int PhantomRenderer::prepareArmor(shared_ptr _mob, int layer, float a) +{ + shared_ptr mob = dynamic_pointer_cast(_mob); + + + if (layer != 0) return -1; + + bindTexture(&PHANTOM_EYES_LOCATION); + float br = 1; + glEnable(GL_BLEND); + +#ifdef _XBOX + glDisable(GL_ALPHA_TEST); +#endif + + + glBlendFunc(GL_ONE, GL_ONE); + glDisable(GL_LIGHTING); + + if (mob->isInvisible()) + { + glDepthMask(false); + } + else + { + glDepthMask(true); + } + + if (SharedConstants::TEXTURE_LIGHTING) + { + int col = 0xf0f0; + int u = col % 65536; + int v = col / 65536; + + glMultiTexCoord2f(GL_TEXTURE1, u / 1.0f, v / 1.0f); + glColor4f(1, 1, 1, 1); + } + + glEnable(GL_LIGHTING); + glColor4f(1, 1, 1, br); + + return 1; +} \ No newline at end of file diff --git a/Minecraft.Client/PhantomRenderer.h b/Minecraft.Client/PhantomRenderer.h new file mode 100644 index 00000000..26de6ef0 --- /dev/null +++ b/Minecraft.Client/PhantomRenderer.h @@ -0,0 +1,27 @@ +#pragma once +#include "MobRenderer.h" + +class PhantomModel; + +class PhantomRenderer : public MobRenderer +{ + static ResourceLocation PHANTOM_LOCATION; + static ResourceLocation PHANTOM_EYES_LOCATION; + int modelVersion; + +public: + PhantomRenderer(); + + virtual void render(shared_ptr mob, + double x, double y, double z, + float rot, float a); + +protected: + virtual ResourceLocation *getTextureLocation(shared_ptr mob); + virtual void scale(shared_ptr mob, float a); + virtual void setupPosition(shared_ptr mob, + double x, double y, double z); + virtual void setupRotations(shared_ptr mob, + float bob, float bodyRot, float a); + virtual int prepareArmor(shared_ptr mob, int layer, float a); +}; \ No newline at end of file diff --git a/Minecraft.Client/Textures.cpp b/Minecraft.Client/Textures.cpp index a8bdec1d..e3b50d4a 100644 --- a/Minecraft.Client/Textures.cpp +++ b/Minecraft.Client/Textures.cpp @@ -175,6 +175,8 @@ const wchar_t *Textures::preLoaded[TN_COUNT] = L"mob/rabbit/white_splotched", L"mob/rabbit/toast", L"mob/rabbit/caerbannog", + L"mob/phantom", + L"mob/phantom_eyes", L"item/trapped", diff --git a/Minecraft.Client/Textures.h b/Minecraft.Client/Textures.h index 55222282..602c09cb 100644 --- a/Minecraft.Client/Textures.h +++ b/Minecraft.Client/Textures.h @@ -165,6 +165,8 @@ typedef enum _TEXTURE_NAME TN_MOB_RABBIT_WHITE_SPLOTCHED, TN_MOB_RABBIT_TOAST, TN_MOB_RABBIT_CAERBANNOG, + TN_MOB_PHANTOM, + TN_MOB_PHANTOM_EYES, TN_TILE_TRAP_CHEST, TN_TILE_LARGE_TRAP_CHEST, diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite1.ogg new file mode 100644 index 00000000..2d3799f6 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite2.ogg new file mode 100644 index 00000000..92201e17 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/bite2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death1.ogg new file mode 100644 index 00000000..bc062e5e Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death2.ogg new file mode 100644 index 00000000..6a301cd8 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death3.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death3.ogg new file mode 100644 index 00000000..cd2f177d Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/death3.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap1.ogg new file mode 100644 index 00000000..aac70caf Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap2.ogg new file mode 100644 index 00000000..4a0b9c67 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap3.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap3.ogg new file mode 100644 index 00000000..b773098a Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap3.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap4.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap4.ogg new file mode 100644 index 00000000..128bdc0a Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap4.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap5.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap5.ogg new file mode 100644 index 00000000..1d1c6821 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap5.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap6.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap6.ogg new file mode 100644 index 00000000..cc700581 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/flap6.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt1.ogg new file mode 100644 index 00000000..ce84c348 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt2.ogg new file mode 100644 index 00000000..bed580e2 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt3.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt3.ogg new file mode 100644 index 00000000..475e4d9d Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/hurt3.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle1.ogg new file mode 100644 index 00000000..3fffda85 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle2.ogg new file mode 100644 index 00000000..76c2ea99 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle3.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle3.ogg new file mode 100644 index 00000000..4decd90c Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle3.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle4.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle4.ogg new file mode 100644 index 00000000..ddfe8148 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle4.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle5.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle5.ogg new file mode 100644 index 00000000..df936806 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/idle5.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop1.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop1.ogg new file mode 100644 index 00000000..88b4723d Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop1.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop2.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop2.ogg new file mode 100644 index 00000000..1a6af4f9 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop2.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop3.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop3.ogg new file mode 100644 index 00000000..d6450800 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop3.ogg differ diff --git a/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop4.ogg b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop4.ogg new file mode 100644 index 00000000..e09801e6 Binary files /dev/null and b/Minecraft.Client/Windows64Media/Sound/Minecraft/mob/phantom/swoop4.ogg differ diff --git a/Minecraft.World/Biome.cpp b/Minecraft.World/Biome.cpp index e4f04a4c..6609e753 100644 --- a/Minecraft.World/Biome.cpp +++ b/Minecraft.World/Biome.cpp @@ -148,9 +148,9 @@ Biome::Biome(int id) : id(id) biomes[id] = this; decorator = createDecorator(); - // -- FIX FIORI ED ERBA GLOBALI -- - decorator->flowerCount = 2; // Valore base di fiori (esclusi biomi speciali che ne sovrascrivono il numero) - decorator->grassCount = 1; // Valore base di erba alta + + decorator->flowerCount = 2; + decorator->grassCount = 1; friendlies.push_back(new MobSpawnerData(eTYPE_SHEEP, 12, 4, 4)); friendlies.push_back(new MobSpawnerData(eTYPE_PIG, 10, 4, 4)); @@ -164,6 +164,7 @@ Biome::Biome(int id) : id(id) enemies.push_back(new MobSpawnerData(eTYPE_SLIME, 10, 4, 4)); enemies.push_back(new MobSpawnerData(eTYPE_ENDERMAN, 1, 1, 4)); enemies.push_back(new MobSpawnerData(eTYPE_WITCH, 1, 1, 1)); + enemies.push_back(new MobSpawnerData(eTYPE_PHANTOM, 5, 1, 2)); waterFriendlies.push_back(new MobSpawnerData(eTYPE_SQUID, 10, 4, 4)); ambientFriendlies.push_back(new MobSpawnerData(eTYPE_BAT, 10, 8, 8)); diff --git a/Minecraft.World/CMakeLists.txt b/Minecraft.World/CMakeLists.txt index 1f3223ef..f849aff9 100644 --- a/Minecraft.World/CMakeLists.txt +++ b/Minecraft.World/CMakeLists.txt @@ -11,7 +11,7 @@ set(MINECRAFT_WORLD_SOURCES ${SOURCES_COMMON} ) -add_library(Minecraft.World STATIC ${MINECRAFT_WORLD_SOURCES} "IceSpikeFeature.cpp" "IceSpikeFeature.h" "BlockBlobFeature.h" "BlockBlobFeature.cpp") +add_library(Minecraft.World STATIC ${MINECRAFT_WORLD_SOURCES} "IceSpikeFeature.cpp" "IceSpikeFeature.h" "BlockBlobFeature.h" "BlockBlobFeature.cpp" "Phantom.h" "Phantom.cpp") target_include_directories(Minecraft.World PRIVATE diff --git a/Minecraft.World/Class.h b/Minecraft.World/Class.h index c4463f66..d8369ac3 100644 --- a/Minecraft.World/Class.h +++ b/Minecraft.World/Class.h @@ -168,6 +168,7 @@ enum eINSTANCEOF eTYPE_BLAZE = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x6, eTYPE_WITCH = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x7, eTYPE_WITHERBOSS = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x8, + eTYPE_PHANTOM = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x9, eTYPE_ENDERMITE = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x10, diff --git a/Minecraft.World/EntityIO.cpp b/Minecraft.World/EntityIO.cpp index bcd0f16c..887dbb45 100644 --- a/Minecraft.World/EntityIO.cpp +++ b/Minecraft.World/EntityIO.cpp @@ -95,6 +95,7 @@ void EntityIO::staticCtor() setId(WitherBoss::create, eTYPE_WITHERBOSS, L"WitherBoss", 64); setId(Bat::create, eTYPE_BAT, L"Bat", 65, eMinecraftColour_Mob_Bat_Colour1, eMinecraftColour_Mob_Bat_Colour2, IDS_BAT); setId(Witch::create, eTYPE_WITCH, L"Witch", 66, eMinecraftColour_Mob_Witch_Colour1, eMinecraftColour_Mob_Witch_Colour2, IDS_WITCH); + setId(Phantom::create, eTYPE_PHANTOM, L"Phantom", 254, eMinecraftColour_Mob_Ghast_Colour1, eMinecraftColour_Mob_Ghast_Colour2, IDS_ZOMBIE); setId(Pig::create, eTYPE_PIG, L"Pig", 90, eMinecraftColour_Mob_Pig_Colour1, eMinecraftColour_Mob_Pig_Colour2, IDS_PIG); setId(Sheep::create, eTYPE_SHEEP, L"Sheep", 91, eMinecraftColour_Mob_Sheep_Colour1, eMinecraftColour_Mob_Sheep_Colour2, IDS_SHEEP); diff --git a/Minecraft.World/Mob.h b/Minecraft.World/Mob.h index f2080f93..62a9661d 100644 --- a/Minecraft.World/Mob.h +++ b/Minecraft.World/Mob.h @@ -45,7 +45,7 @@ public: protected: int xpReward; -private: +protected: LookControl *lookControl; MoveControl *moveControl; JumpControl *jumpControl; diff --git a/Minecraft.World/Phantom.cpp b/Minecraft.World/Phantom.cpp new file mode 100644 index 00000000..a4449359 --- /dev/null +++ b/Minecraft.World/Phantom.cpp @@ -0,0 +1,462 @@ + +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.goal.target.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.level.tile.h" +#include "LevelEvent.h" +#include "SoundTypes.h" +#include "Phantom.h" + + + +class PhantomMoveControl : public MoveControl { + Phantom* phantom; +public: + PhantomMoveControl(Phantom* p) : MoveControl(p), phantom(p) {} + + void tick() override { + if (phantom->horizontalCollision) { + phantom->yRot += 180.0f; + phantom->flySpeed = 0.1f; + } + + double d0 = phantom->moveTargetX - phantom->x; + double d1 = phantom->moveTargetY - phantom->y; + double d2 = phantom->moveTargetZ - phantom->z; + double d3 = sqrt(d0 * d0 + d2 * d2); + + if (abs(d3) > 1.0e-5) { + double d4 = 1.0 - abs(d1 * 0.7) / d3; + d0 *= d4; + d2 *= d4; + d3 = sqrt(d0 * d0 + d2 * d2); + double d5 = sqrt(d0 * d0 + d2 * d2 + d1 * d1); + + float f1 = (float)(atan2(d2, d0) * 180.0 / PI); + float f2 = Mth::wrapDegrees(phantom->yRot + 90.0f); + float f3 = Mth::wrapDegrees(f1); + + float diff = Mth::wrapDegrees(f3 - f2); + phantom->yRot = f2 + Mth::clamp(diff, -4.0f, 4.0f) - 90.0f; + phantom->yBodyRot = phantom->yRot; + + if (abs(diff) < 3.0f) { + phantom->flySpeed += Mth::clamp(1.8f - phantom->flySpeed, -0.005f * (1.8f / max(phantom->flySpeed, 0.001f)), 0.005f * (1.8f / max(phantom->flySpeed, 0.001f))); + } else { + phantom->flySpeed += Mth::clamp(0.2f - phantom->flySpeed, -0.025f, 0.025f); + } + + float f4 = (float)(-(atan2(-d1, d3) * 180.0 / PI)); + phantom->xRot = f4; + + float f5_rad = (phantom->yRot + 90.0f) * (float)(PI / 180.0); + float f4_rad = f4 * (float)(PI / 180.0); + + double d6 = phantom->flySpeed * cos(f5_rad) * abs(d0 / d5); + double d7 = phantom->flySpeed * sin(f5_rad) * abs(d2 / d5); + double d8 = phantom->flySpeed * sin(f4_rad) * abs(d1 / d5); + + phantom->xd += (d6 - phantom->xd) * 0.2; + phantom->yd += (d8 - phantom->yd) * 0.2; + phantom->zd += (d7 - phantom->zd) * 0.2; + } + } +}; + +class PhantomAttackStrategyGoal : public Goal { + Phantom* phantom; + int nextSweepTick; +public: + PhantomAttackStrategyGoal(Phantom* p) : phantom(p), nextSweepTick(0) {} + + bool canUse() override { + shared_ptr target = phantom->getTarget(); + return target != nullptr && target->isAlive(); + } + + void start() override { + nextSweepTick = 10 * 20; // About 10 seconds + phantom->attackPhase = Phantom::AttackPhase::CIRCLE; + setAnchorAboveTarget(); + } + + void stop() override { + if (phantom->hasAnchor) { + phantom->anchorY = phantom->level->getTopSolidBlock(phantom->anchorX, phantom->anchorZ) + 10 + phantom->random->nextInt(20); + } + } + + void tick() override { + if (phantom->attackPhase == Phantom::AttackPhase::CIRCLE) { + nextSweepTick--; + if (nextSweepTick <= 0) { + phantom->attackPhase = Phantom::AttackPhase::SWOOP; + setAnchorAboveTarget(); + nextSweepTick = (8 + phantom->random->nextInt(4)) * 20; + phantom->level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int)phantom->x, (int)phantom->y, (int)phantom->z, 0); + } + } + } + +private: + void setAnchorAboveTarget() { + shared_ptr target = phantom->getTarget(); + if (target != nullptr) { + phantom->anchorX = Mth::floor(target->x); + phantom->anchorY = Mth::floor(target->y) + 20 + phantom->random->nextInt(20); + phantom->anchorZ = Mth::floor(target->z); + if (phantom->anchorY < phantom->level->seaLevel) { + phantom->anchorY = phantom->level->seaLevel + 1; + } + phantom->hasAnchor = true; + } + } +}; + +class PhantomSweepAttackGoal : public Goal { + Phantom* phantom; +public: + PhantomSweepAttackGoal(Phantom* p) : phantom(p) {} + + bool canUse() override { + return phantom->getTarget() != nullptr && phantom->attackPhase == Phantom::AttackPhase::SWOOP; + } + + bool canContinueToUse() override { + shared_ptr target = phantom->getTarget(); + if (target == nullptr || !target->isAlive()) return false; + return canUse(); + } + + void stop() override { + phantom->setTarget(nullptr); + phantom->attackPhase = Phantom::AttackPhase::CIRCLE; + } + + void tick() override { + shared_ptr target = phantom->getTarget(); + if (target != nullptr) { + phantom->moveTargetX = target->x; + phantom->moveTargetY = target->y + (target->bbHeight * 0.5); + phantom->moveTargetZ = target->z; + + // Hit control + double dx = phantom->x - target->x; + double dy = phantom->y - target->y; + double dz = phantom->z - target->z; + if (sqrt(dx*dx + dy*dy + dz*dz) < 2.0) { // Close range + phantom->doHurtTarget(target); + phantom->playSound(eSoundType_MOB_PHANTOM_BITE, 1.0f, 1.0f); + phantom->attackPhase = Phantom::AttackPhase::CIRCLE; + phantom->level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int)phantom->x, (int)phantom->y, (int)phantom->z, 0); + } else if (phantom->horizontalCollision || phantom->hurtTime > 0) { + phantom->attackPhase = Phantom::AttackPhase::CIRCLE; + } + } + } +}; + +class PhantomCircleAroundAnchorGoal : public Goal { + Phantom* phantom; +public: + PhantomCircleAroundAnchorGoal(Phantom* p) : phantom(p) {} + + bool canUse() override { + return phantom->getTarget() == nullptr || phantom->attackPhase == Phantom::AttackPhase::CIRCLE; + } + + void start() override { + phantom->circleDistance = 5.0f + phantom->random->nextFloat() * 10.0f; + phantom->circleHeight = -4.0f + phantom->random->nextFloat() * 9.0f; + phantom->circleClockwise = phantom->random->nextBoolean() ? 1.0f : -1.0f; + selectNext(); + } + + void tick() override { + if (phantom->random->nextInt(350) == 0) phantom->circleHeight = -4.0f + phantom->random->nextFloat() * 9.0f; + + if (phantom->random->nextInt(250) == 0) { + phantom->circleDistance++; + if (phantom->circleDistance > 15.0f) { + phantom->circleDistance = 5.0f; + phantom->circleClockwise = -phantom->circleClockwise; + } + } + + if (phantom->random->nextInt(450) == 0) { + phantom->circleAngle = phantom->random->nextFloat() * 2.0f * (float)PI; + selectNext(); + } + + if (phantom->isTouchingMoveTarget()) selectNext(); + + // Height control to avoid crashing + if (phantom->moveTargetY < phantom->y && !phantom->level->isEmptyTile(Mth::floor(phantom->x), Mth::floor(phantom->y) - 1, Mth::floor(phantom->z))) { + phantom->circleHeight = max(1.0f, phantom->circleHeight); + selectNext(); + } + if (phantom->moveTargetY > phantom->y && !phantom->level->isEmptyTile(Mth::floor(phantom->x), Mth::floor(phantom->y) + 1, Mth::floor(phantom->z))) { + phantom->circleHeight = min(-1.0f, phantom->circleHeight); + selectNext(); + } + } + +private: + void selectNext() { + if (!phantom->hasAnchor) { + phantom->anchorX = Mth::floor(phantom->x); + phantom->anchorY = Mth::floor(phantom->y); + phantom->anchorZ = Mth::floor(phantom->z); + phantom->hasAnchor = true; + } + + phantom->circleAngle += phantom->circleClockwise * 15.0f * (float)(PI / 180.0); + phantom->moveTargetX = phantom->anchorX + 0.5 + phantom->circleDistance * cos(phantom->circleAngle); + phantom->moveTargetY = phantom->anchorY - 4.0 + phantom->circleHeight; + phantom->moveTargetZ = phantom->anchorZ + 0.5 + phantom->circleDistance * sin(phantom->circleAngle); + phantom->moveTargetInitialized = true; + } +}; + + +class PhantomAttackPlayerTargetGoal : public Goal { + Phantom* phantom; + int nextScanTick; +public: + PhantomAttackPlayerTargetGoal(Phantom* p) : phantom(p), nextScanTick(20) {} + + bool canUse() override { + if (nextScanTick > 0) { + nextScanTick--; + return false; + } + nextScanTick = 60; + + + shared_ptr player = phantom->level->getNearestAttackablePlayer(phantom->shared_from_this(), 64.0); + if (player != nullptr) { + phantom->setTarget(player); + return true; + } + return false; + } + + bool canContinueToUse() override { + shared_ptr target = phantom->getTarget(); + return target != nullptr && target->isAlive(); + } +}; + + + +Phantom::Phantom(Level *level) : FlyingMob(level) +{ + this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + xpReward = Enemy::XP_REWARD_SMALL; + setSize(0.9f, 0.5f); + + moveTargetX = 0.0; + moveTargetY = 0.0; + moveTargetZ = 0.0; + moveTargetInitialized = false; + + hasAnchor = false; + anchorX = anchorY = anchorZ = 0; + anchorHeight = 10 + random->nextInt(10); + + attackPhase = AttackPhase::CIRCLE; + circleAngle = 0.0f; + circleDistance = 5.0f; + circleHeight = 0.0f; + circleClockwise = 1.0f; + + flySpeed = 0.1f; + phantomSize = 0; + + + delete moveControl; + moveControl = new PhantomMoveControl(this); + + + goalSelector.addGoal(1, new PhantomAttackStrategyGoal(this)); + goalSelector.addGoal(2, new PhantomSweepAttackGoal(this)); + goalSelector.addGoal(3, new PhantomCircleAroundAnchorGoal(this)); + + + targetSelector.addGoal(1, new PhantomAttackPlayerTargetGoal(this)); +} + +void Phantom::setPhantomSize(int size) +{ + phantomSize = Mth::clamp(size, 0, 64); + float scale = 1.0f + 0.15f * phantomSize; + setSize(0.9f * scale, 0.5f * scale); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(6.0 + phantomSize); +} + +void Phantom::defineSynchedData() +{ + FlyingMob::defineSynchedData(); +} + +void Phantom::registerAttributes() +{ + FlyingMob::registerAttributes(); + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(20.0); + getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(6.0); +} + +float Phantom::getSoundVolume() { return 1.0f; } +float Phantom::getVoicePitch() { return FlyingMob::getVoicePitch(); } +int Phantom::getAmbientSound() { return eSoundType_MOB_PHANTOM_IDLE; } +int Phantom::getHurtSound() { return eSoundType_MOB_PHANTOM_HURT; } +int Phantom::getDeathSound() { return eSoundType_MOB_PHANTOM_DEATH; } + +bool Phantom::isPushable() { return false; } +void Phantom::doPush(shared_ptr e) { } +void Phantom::pushEntities() { } +bool Phantom::makeStepSound() { return false; } +void Phantom::causeFallDamage(float distance) { } +void Phantom::checkFallDamage(double ya, bool onGround) { } +bool Phantom::isIgnoringTileTriggers() { return true; } +bool Phantom::onLadder() { return false; } + +void Phantom::tick() +{ + + if (!level->isClientSide && isAlive()) + { + + if (Calendar::GetMonth() + 1 != 4 || Calendar::GetDayOfMonth() != 1) + { + + remove(); + return; + + + hurt(DamageSource::magic, getMaxHealth()); + } + } + + FlyingMob::tick(); + yBodyRot = yRot; + + if (!level->isClientSide && isAlive() && tickCount % 20 == 0) + { + playSound(eSoundType_MOB_PHANTOM_FLAP, 1.0f, 1.0f); + } + + + if (!level->isClientSide && isAlive()) + { + + if (level->isDay() && !level->isRaining()) + { + float br = getBrightness(1.0f); + if (br > 0.5f && level->canSeeSky( + Mth::floor(x), static_cast(floor(y + 0.5)), Mth::floor(z))) + { + setOnFire(8); + } + } + } +} + +void Phantom::initAnchor(int bx, int by, int bz) +{ + anchorX = bx; + anchorY = by; + anchorZ = bz; + hasAnchor = true; +} + +bool Phantom::isTouchingMoveTarget() const +{ + double dx = moveTargetX - x; + double dy = moveTargetY - y; + double dz = moveTargetZ - z; + return (dx * dx + dy * dy + dz * dz) < 4.0; +} + +bool Phantom::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + return FlyingMob::hurt(source, dmg); +} + +bool Phantom::doHurtTarget(shared_ptr target) +{ + float damage = (float)getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->getValue(); + return target->hurt(DamageSource::mobAttack(dynamic_pointer_cast(shared_from_this())), damage); +} + +void Phantom::readAdditionalSaveData(CompoundTag *tag) +{ + FlyingMob::readAdditionalSaveData(tag); + setPhantomSize(tag->getInt(L"Size")); + if (tag->contains(L"AnchorX")) + { + anchorX = tag->getInt(L"AnchorX"); + anchorY = tag->getInt(L"AnchorY"); + anchorZ = tag->getInt(L"AnchorZ"); + hasAnchor = true; + } + anchorHeight = 10 + random->nextInt(10); + moveTargetInitialized = false; +} + +void Phantom::addAdditonalSaveData(CompoundTag *entityTag) +{ + FlyingMob::addAdditonalSaveData(entityTag); + entityTag->putInt(L"Size", phantomSize); + if (hasAnchor) + { + entityTag->putInt(L"AnchorX", anchorX); + entityTag->putInt(L"AnchorY", anchorY); + entityTag->putInt(L"AnchorZ", anchorZ); + } +} + +bool Phantom::canSpawn() +{ + if (Calendar::GetMonth() + 1 != 4 || Calendar::GetDayOfMonth() != 1) { + return false; + } + int xt = Mth::floor(x); + int yt = static_cast(y); + int zt = Mth::floor(z); + + //if (yt < level->seaLevel) return false; + if (level->isDay()) return false; + //if (!level->canSeeSky(xt, yt, zt)) return false; + if (level->getRawBrightness(xt, yt, zt) >= 8) return false; + + int topSolidY = level->getTopSolidBlock(xt, zt); + if (topSolidY < level->seaLevel) { + topSolidY = level->seaLevel; + } + if (yt <= topSolidY + 5) + { + int heightBoost = 20 + random->nextInt(15); + yt = topSolidY + heightBoost; + + + setPos(x, (double)yt, z); + } + if (!level->canSeeSky(xt, yt, zt)) return false; + + return FlyingMob::canSpawn(); +} + diff --git a/Minecraft.World/Phantom.h b/Minecraft.World/Phantom.h new file mode 100644 index 00000000..864e1d8f --- /dev/null +++ b/Minecraft.World/Phantom.h @@ -0,0 +1,85 @@ +#pragma once +using namespace std; +#include "FlyingMob.h" +#include "Enemy.h" + +class Level; +class CompoundTag; +class DamageSource; +class Player; + +class Phantom : public FlyingMob, public Enemy +{ + + friend class PhantomMoveControl; + friend class PhantomAttackStrategyGoal; + friend class PhantomCircleAroundAnchorGoal; + friend class PhantomSweepAttackGoal; + +public: + eINSTANCEOF GetType() { return eTYPE_PHANTOM; } + static Entity *create(Level *level) { return new Phantom(level); } + enum class AttackPhase { CIRCLE, SWOOP }; + +private: + int phantomSize; + + + double moveTargetX, moveTargetY, moveTargetZ; + bool moveTargetInitialized; + + // Orbit anchor + int anchorX, anchorY, anchorZ; + bool hasAnchor; + int anchorHeight; + + // Attack + AttackPhase attackPhase; + + //Circle + float circleAngle; + float circleDistance; + float circleHeight; + float circleClockwise; + + float flySpeed; + +public: + Phantom(Level *level); + + int getPhantomSize() const { return phantomSize; } + void setPhantomSize(int size); + AttackPhase getAttackPhase() const { return attackPhase; } + + virtual bool isPushable(); + virtual void tick(); + virtual bool hurt(DamageSource *source, float dmg); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *entityTag); + virtual bool canSpawn(); + virtual bool doHurtTarget(shared_ptr target) override; + +protected: + virtual void defineSynchedData(); + virtual void registerAttributes(); + virtual float getSoundVolume(); + virtual float getVoicePitch(); + virtual int getAmbientSound(); + virtual int getHurtSound(); + virtual int getDeathSound(); + + + virtual bool useNewAi() override { return true; } + + virtual void doPush(shared_ptr e); + virtual void pushEntities(); + virtual bool makeStepSound(); + virtual void causeFallDamage(float distance); + virtual void checkFallDamage(double ya, bool onGround); + virtual bool isIgnoringTileTriggers(); + virtual bool onLadder(); + +private: + void initAnchor(int bx, int by, int bz); + bool isTouchingMoveTarget() const; +}; \ No newline at end of file diff --git a/Minecraft.World/SoundTypes.h b/Minecraft.World/SoundTypes.h index 2ec7d9ee..a69e4646 100644 --- a/Minecraft.World/SoundTypes.h +++ b/Minecraft.World/SoundTypes.h @@ -58,14 +58,14 @@ enum eSOUND_TYPE eSoundType_MOB_CAT_PURREOW, eSoundType_MOB_CAT_MEOW, eSoundType_MOB_CAT_HIT, -// eSoundType_MOB_IRONGOLEM_THROW, -// eSoundType_MOB_IRONGOLEM_HIT, -// eSoundType_MOB_IRONGOLEM_DEATH, -// eSoundType_MOB_IRONGOLEM_WALK, + // eSoundType_MOB_IRONGOLEM_THROW, + // eSoundType_MOB_IRONGOLEM_HIT, + // eSoundType_MOB_IRONGOLEM_DEATH, + // eSoundType_MOB_IRONGOLEM_WALK, eSoundType_RANDOM_BOW, eSoundType_RANDOM_BOW_HIT, eSoundType_RANDOM_EXPLODE, - eSoundType_RANDOM_FIZZ, + eSoundType_RANDOM_FIZZ, eSoundType_RANDOM_POP, eSoundType_RANDOM_FUSE, eSoundType_RANDOM_DRINK, @@ -217,7 +217,13 @@ enum eSOUND_TYPE eSoundType_MOB_RABBIT_HURT, eSoundType_MOB_RABBIT_DEATH, eSoundType_MOB_RABBIT_HOP, - + + eSoundType_MOB_PHANTOM_BITE, +eSoundType_MOB_PHANTOM_DEATH, +eSoundType_MOB_PHANTOM_FLAP, +eSoundType_MOB_PHANTOM_HURT, +eSoundType_MOB_PHANTOM_IDLE, +eSoundType_MOB_PHANTOM_SWOOP, eSoundType_MAX }; diff --git a/Minecraft.World/net.minecraft.world.entity.monster.h b/Minecraft.World/net.minecraft.world.entity.monster.h index e016dcf1..ede4330b 100644 --- a/Minecraft.World/net.minecraft.world.entity.monster.h +++ b/Minecraft.World/net.minecraft.world.entity.monster.h @@ -27,4 +27,5 @@ #include "Witch.h" //TU 31 -#include "Endermite.h" \ No newline at end of file +#include "Endermite.h" +#include "Phantom.h" \ No newline at end of file