diff options
Diffstat (limited to 'src')
30 files changed, 593 insertions, 91 deletions
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index a847f1b65..297d5273e 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -105,7 +105,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width); double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width); - if (m_World->SpawnMob(MobX, DispY, MobZ, static_cast<eMonsterType>(m_Contents.GetSlot(a_SlotNum).m_ItemDamage)) != cEntity::INVALID_ID) + if (m_World->SpawnMob(MobX, DispY, MobZ, static_cast<eMonsterType>(m_Contents.GetSlot(a_SlotNum).m_ItemDamage), false) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index c18acbdb5..4af50984e 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -49,7 +49,7 @@ public: int PosX = a_Chunk.GetPosX() * cChunkDef::Width + a_RelX; int PosZ = a_Chunk.GetPosZ() * cChunkDef::Width + a_RelZ; - a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, mtZombiePigman); + a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, mtZombiePigman, false); } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 826df7034..ede0837a4 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -35,7 +35,7 @@ public: /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, or cEntity::INVALID_ID on failure. */ - virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0; + virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby) = 0; /** Spawns an experience orb at the given location with the given reward. Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c8fe7d0c..d941b7d4c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ SET (SRCS ChunkSender.cpp ChunkStay.cpp ClientHandle.cpp + Color.cpp CommandOutput.cpp CompositeChat.cpp CraftingRecipes.cpp diff --git a/src/Color.cpp b/src/Color.cpp new file mode 100644 index 000000000..f2180e2d9 --- /dev/null +++ b/src/Color.cpp @@ -0,0 +1,76 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Color.h" + + + + + +#define COLOR_RED_BITS 0x00FF0000 +#define COLOR_GREEN_BITS 0x0000FF00 +#define COLOR_BLUE_BITS 0x000000FF +#define COLOR_RED_OFFSET 16 +#define COLOR_GREEN_OFFSET 8 + + + + + +void cColor::SetColor(unsigned char a_Red, unsigned char a_Green, unsigned char a_Blue) +{ + m_Color = (static_cast<unsigned int>(a_Red) << COLOR_RED_OFFSET) + (static_cast<unsigned int>(a_Green) << COLOR_GREEN_OFFSET) + (static_cast<unsigned int>(a_Blue)); +} + + + + + +void cColor::SetRed(unsigned char a_Red) +{ + m_Color = (static_cast<unsigned int>(a_Red) << COLOR_RED_OFFSET) + ((COLOR_GREEN_BITS | COLOR_BLUE_BITS) & m_Color); +} + + + + + +void cColor::SetGreen(unsigned char a_Green) +{ + m_Color = (static_cast<unsigned int>(a_Green) << COLOR_GREEN_OFFSET) + ((COLOR_RED_BITS | COLOR_BLUE_BITS) & m_Color); +} + + + + + +void cColor::SetBlue(unsigned char a_Blue) +{ + m_Color = static_cast<unsigned int>(a_Blue) + ((COLOR_RED_BITS | COLOR_GREEN_BITS) & m_Color); +} + + + + + +unsigned char cColor::GetRed() const +{ + return (m_Color & COLOR_RED_BITS) >> COLOR_RED_OFFSET; +} + + + + + +unsigned char cColor::GetGreen() const +{ + return (m_Color & COLOR_GREEN_BITS) >> COLOR_GREEN_OFFSET; +} + + + + + +unsigned char cColor::GetBlue() const +{ + return m_Color & COLOR_BLUE_BITS; +} diff --git a/src/Color.h b/src/Color.h new file mode 100644 index 000000000..a90e8372b --- /dev/null +++ b/src/Color.h @@ -0,0 +1,58 @@ + +// Color.h + +// Declares a class to handle item color related code + + + + + +#pragma once + + // tolua_begin + +class cColor +{ +public: + + enum + { + COLOR_MIN = 0, + COLOR_MAX = 255, + COLOR_LIMIT = 256, + COLOR_NONE = 0xFFFFFFFF, + }; + cColor() { m_Color = COLOR_NONE;} + cColor(unsigned char a_Red, unsigned char a_Green, unsigned char a_Blue) { SetColor(a_Red, a_Green, a_Blue); } + + /// Returns whether the color is a valid color + bool IsValid() const { return m_Color != COLOR_NONE; } + + /// Changes the color + void SetColor(unsigned char a_Red, unsigned char a_Green, unsigned char a_Blue); + + /// Alters the red value of the color + void SetRed(unsigned char a_Red); + + /// Alters the green value of the color + void SetGreen(unsigned char a_Red); + + /// Alters the blue value of the color + void SetBlue(unsigned char a_Red); + + /// Returns the red value of the color + unsigned char GetRed() const; + + /// Returns the green value of the color + unsigned char GetGreen() const; + + /// Returns the blue value of the color + unsigned char GetBlue() const; + + /// Resets the color + void Clear() { m_Color = COLOR_NONE; } + // tolua_end + + unsigned int m_Color; + +}; diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 0bb77d341..d3a28292a 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -787,6 +787,9 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti // We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY); + // Handle Dyed Leather + HandleDyedLeather(a_CraftingGrid, Recipe.get(), a_GridStride, a_GridWidth, a_GridHeight); + return Recipe.release(); } @@ -874,3 +877,192 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe + +void cCraftingRecipes::HandleDyedLeather(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_GridWidth, int a_GridHeight) +{ + short result_type = a_Recipe->m_Result.m_ItemType; + if ((result_type == E_ITEM_LEATHER_CAP) || (result_type == E_ITEM_LEATHER_TUNIC) || (result_type == E_ITEM_LEATHER_PANTS) || (result_type == E_ITEM_LEATHER_BOOTS)) + { + bool found = false; + cItem temp; + + float red = 0; + float green = 0; + float blue = 0; + float dye_count = 0; + + for (int x = 0; x < a_GridWidth; ++x) + { + for (int y = 0; y < a_GridHeight; ++y) + { + int GridIdx = x + a_GridStride * y; + if ((a_CraftingGrid[GridIdx].m_ItemType == result_type) && (found == false)) + { + found = true; + temp = a_CraftingGrid[GridIdx].CopyOne(); + // The original color of the item affects the result + if (temp.m_ItemColor.IsValid()) + { + red += temp.m_ItemColor.GetRed(); + green += temp.m_ItemColor.GetGreen(); + blue += temp.m_ItemColor.GetBlue(); + ++dye_count; + } + } + else if (a_CraftingGrid[GridIdx].m_ItemType == E_ITEM_DYE) + { + switch (a_CraftingGrid[GridIdx].m_ItemDamage) + { + case E_META_DYE_BLACK: + { + red += 23; + green += 23; + blue += 23; + break; + } + case E_META_DYE_RED: + { + red += 142; + green += 47; + blue += 47; + break; + } + case E_META_DYE_GREEN: + { + red += 95; + green += 118; + blue += 47; + break; + } + case E_META_DYE_BROWN: + { + red += 95; + green += 71; + blue += 47; + break; + } + case E_META_DYE_BLUE: + { + red += 47; + green += 71; + blue += 165; + break; + } + case E_META_DYE_PURPLE: + { + red += 118; + green += 59; + blue += 165; + break; + } + case E_META_DYE_CYAN: + { + red += 71; + green += 118; + blue += 142; + break; + } + case E_META_DYE_LIGHTGRAY: + { + red += 142; + green += 142; + blue += 142; + break; + } + case E_META_DYE_GRAY: + { + red += 71; + green += 71; + blue += 71; + break; + } + case E_META_DYE_PINK: + { + red += 225; + green += 118; + blue += 153; + break; + } + case E_META_DYE_LIGHTGREEN: + { + red += 118; + green += 190; + blue += 23; + break; + } + case E_META_DYE_YELLOW: + { + red += 213; + green += 213; + blue += 47; + break; + } + case E_META_DYE_LIGHTBLUE: + { + red += 95; + green += 142; + blue += 201; + break; + } + case E_META_DYE_MAGENTA: + { + red += 165; + green += 71; + blue += 201; + break; + } + case E_META_DYE_ORANGE: + { + red += 201; + green += 118; + blue += 47; + break; + } + case E_META_DYE_WHITE: + { + red += 237; + green += 237; + blue += 237; + break; + } + } + ++dye_count; + } + else if (a_CraftingGrid[GridIdx].m_ItemType != E_ITEM_EMPTY) + { + return; + } + } + } + + if (!found) + { + return; + } + + // Calculate the rgb values + double maximum = static_cast<double>(std::max({red, green, blue})); + + double average_red = red / dye_count; + double average_green = green / dye_count; + double average_blue = blue / dye_count; + double average_max = maximum / dye_count; + + double max_average = std::max({average_red, average_green, average_blue}); + + double gain_factor = average_max / max_average; + + + unsigned char result_red = static_cast<unsigned char>(average_red * gain_factor); + unsigned char result_green = static_cast<unsigned char>(average_green * gain_factor); + unsigned char result_blue = static_cast<unsigned char>(average_blue * gain_factor); + + // Set the results values + a_Recipe->m_Result = temp; + a_Recipe->m_Result.m_ItemColor.SetColor(result_red, result_green, result_blue); + } +} + + + + diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h index 44444d42e..778dd495a 100644 --- a/src/CraftingRecipes.h +++ b/src/CraftingRecipes.h @@ -168,6 +168,9 @@ protected: /** Searches for anything firework related, and does the data setting if appropriate */ void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY); + + /// Searches for anything dye related for leather, calculates the appropriate color value, and sets the resulting value. + void HandleDyedLeather(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_GridWidth, int a_GridHeight); } ; diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp index e9ef29239..91bca1da7 100644 --- a/src/Entities/ThrownEggEntity.cpp +++ b/src/Entities/ThrownEggEntity.cpp @@ -69,13 +69,13 @@ void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos) { if (m_World->GetTickRandomNumber(7) == 1) { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, false); } else if (m_World->GetTickRandomNumber(32) == 1) { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, false); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, false); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, false); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, false); } } diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index 092d71182..b0363e050 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -106,6 +106,7 @@ void GetLargeJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & /// Generates an image of a small jungle tree (1x1 trunk) void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); +/// Moves the x and z coordinants to the north-west corner of a 2x2 of saplings. Returns true if a 2x2 was found, otherwise it returns false bool GetLargeTreeAdjustment(cWorld & a_World, int & a_X, int & a_Y, int & a_Z, NIBBLETYPE a_Meta); diff --git a/src/Item.cpp b/src/Item.cpp index 36c444328..7bd344ae8 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -142,6 +142,13 @@ void cItem::GetJson(Json::Value & a_OutValue) const a_OutValue["Lore"] = m_Lore; } + if (m_ItemColor.IsValid()) + { + a_OutValue["Color_Red"] = m_ItemColor.GetRed(); + a_OutValue["Color_Green"] = m_ItemColor.GetGreen(); + a_OutValue["Color_Blue"] = m_ItemColor.GetBlue(); + } + if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR)) { a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker; @@ -172,6 +179,18 @@ void cItem::FromJson(const Json::Value & a_Value) m_CustomName = a_Value.get("Name", "").asString(); m_Lore = a_Value.get("Lore", "").asString(); + int red = a_Value.get("Color_Red", -1).asInt(); + int green = a_Value.get("Color_Green", -1).asInt(); + int blue = a_Value.get("Color_Blue", -1).asInt(); + if ((red > -1) && (red < static_cast<int>(cColor::COLOR_LIMIT)) && (green > -1) && (green < static_cast<int>(cColor::COLOR_LIMIT)) && (blue > -1) && (blue < static_cast<int>(cColor::COLOR_LIMIT))) + { + m_ItemColor.SetColor(static_cast<unsigned char>(red), static_cast<unsigned char>(green), static_cast<unsigned char>(blue)); + } + else if ((red != -1) || (blue != -1) || (green != -1)) + { + LOGWARNING("Item with invalid red, green, and blue values read in from json file."); + } + if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR)) { m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool(); diff --git a/src/Item.h b/src/Item.h index 056b5eb8a..8f47c4177 100644 --- a/src/Item.h +++ b/src/Item.h @@ -12,6 +12,7 @@ #include "Defines.h" #include "Enchantments.h" #include "WorldStorage/FireworksSerializer.h" +#include "Color.h" @@ -19,6 +20,7 @@ // fwd: class cItemHandler; +class cColor; namespace Json { @@ -41,7 +43,8 @@ public: m_CustomName(""), m_Lore(""), m_RepairCost(0), - m_FireworkItem() + m_FireworkItem(), + m_ItemColor() { } @@ -62,7 +65,8 @@ public: m_CustomName (a_CustomName), m_Lore (a_Lore), m_RepairCost (0), - m_FireworkItem() + m_FireworkItem(), + m_ItemColor() { if (!IsValidItem(m_ItemType)) { @@ -105,6 +109,7 @@ public: m_Lore = ""; m_RepairCost = 0; m_FireworkItem.EmptyData(); + m_ItemColor.Clear(); } @@ -114,6 +119,7 @@ public: m_ItemCount = 0; m_ItemDamage = 0; m_RepairCost = 0; + m_ItemColor.Clear(); } @@ -206,6 +212,7 @@ public: int m_RepairCost; cFireworkItem m_FireworkItem; + cColor m_ItemColor; }; // tolua_end diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index 9a4044bc0..e0f72be9b 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -278,7 +278,7 @@ public: // Spawn the wither: int BlockX = a_PlacedHeadX + a_OffsetX; int BlockZ = a_PlacedHeadZ + a_OffsetZ; - a_World.SpawnMob(static_cast<double>(BlockX) + 0.5, a_PlacedHeadY - 2, static_cast<double>(BlockZ) + 0.5, mtWither); + a_World.SpawnMob(static_cast<double>(BlockX) + 0.5, a_PlacedHeadY - 2, static_cast<double>(BlockZ) + 0.5, mtWither, false); AwardSpawnWitherAchievement(a_World, BlockX, a_PlacedHeadY - 2, BlockZ); return true; } diff --git a/src/Items/ItemPumpkin.h b/src/Items/ItemPumpkin.h index fa00179d3..7a53d522f 100644 --- a/src/Items/ItemPumpkin.h +++ b/src/Items/ItemPumpkin.h @@ -96,7 +96,7 @@ public: } // Spawn the golem: - a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem); + a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem, false); return true; } @@ -142,7 +142,7 @@ public: } // Spawn the golem: - a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem); + a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem, false); return true; } // for i - ArmOffsets[] diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index b67fe074d..85dd2d245 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -40,7 +40,7 @@ public: eMonsterType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); if ( (MonsterType != mtInvalidType) && // Valid monster type - (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) != cEntity::INVALID_ID)) // Spawning succeeded + (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType, false) != cEntity::INVALID_ID)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 2832a1570..d5de3b19e 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -115,9 +115,11 @@ public: virtual bool IsTame (void) const { return false; } virtual bool IsSitting (void) const { return false; } + // tolua_begin bool IsBaby (void) const { return m_Age < 0; } char GetAge (void) const { return m_Age; } void SetAge(char a_Age) { m_Age = a_Age; } + // tolua_end // tolua_begin diff --git a/src/Mobs/Mooshroom.cpp b/src/Mobs/Mooshroom.cpp index 3b2fbad57..08cabe143 100644 --- a/src/Mobs/Mooshroom.cpp +++ b/src/Mobs/Mooshroom.cpp @@ -67,7 +67,7 @@ void cMooshroom::OnRightClicked(cPlayer & a_Player) cItems Drops; Drops.push_back(cItem(E_BLOCK_RED_MUSHROOM, 5, 0)); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); - m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtCow); + m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtCow, false); Destroy(); } break; } diff --git a/src/Mobs/Pig.cpp b/src/Mobs/Pig.cpp index efa779ac2..21c8e923a 100644 --- a/src/Mobs/Pig.cpp +++ b/src/Mobs/Pig.cpp @@ -108,7 +108,7 @@ bool cPig::DoTakeDamage(TakeDamageInfo & a_TDI) if (a_TDI.DamageType == dtLightning) { Destroy(); - m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtZombiePigman); + m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtZombiePigman, false); return true; } return true; diff --git a/src/Mobs/Rabbit.cpp b/src/Mobs/Rabbit.cpp index c7f3d58f0..9d10212bf 100644 --- a/src/Mobs/Rabbit.cpp +++ b/src/Mobs/Rabbit.cpp @@ -10,7 +10,20 @@ cRabbit::cRabbit(void) : - super("Rabbit", mtRabbit, "mob.rabbit.idle", "mob.rabbit.death", 0.82, 0.68) + cRabbit(static_cast<eRabbitType>(cFastRandom().NextInt( + static_cast<UInt8>(eRabbitType::SaltAndPepper) + 1 // Max possible Rabbit-Type + )), 0) +{ +} + + + + + +cRabbit::cRabbit(eRabbitType Type, int MoreCarrotTicks) : + super("Rabbit", mtRabbit, "mob.rabbit.idle", "mob.rabbit.death", 0.82, 0.68), + m_Type(Type), + m_MoreCarrotTicks(MoreCarrotTicks) { } diff --git a/src/Mobs/Rabbit.h b/src/Mobs/Rabbit.h index e86c85579..56181e3d0 100644 --- a/src/Mobs/Rabbit.h +++ b/src/Mobs/Rabbit.h @@ -7,6 +7,21 @@ +enum class eRabbitType : UInt8 +{ + Brown = 0, + White = 1, + Black = 2, + BlackAndWhite = 3, + Gold = 4, + SaltAndPepper = 5, + TheKillerBunny = 99 +}; + + + + + class cRabbit : public cPassiveMonster { @@ -14,11 +29,19 @@ class cRabbit : public: cRabbit(); + cRabbit(eRabbitType Type, int MoreCarrotTicks = 0); CLASS_PROTODEF(cRabbit) virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; - virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_CARROT); } + eRabbitType GetRabbitType() const { return m_Type; } + UInt8 GetRabbitTypeAsNumber() const { return static_cast<UInt8>(GetRabbitType()); } + int GetMoreCarrotTicks() const { return m_MoreCarrotTicks; } + +private: + + eRabbitType m_Type; + int m_MoreCarrotTicks; // Ticks until the Rabbit eat planted Carrots } ; diff --git a/src/Mobs/Spider.cpp b/src/Mobs/Spider.cpp index 184a1d912..a9da28750 100644 --- a/src/Mobs/Spider.cpp +++ b/src/Mobs/Spider.cpp @@ -3,7 +3,8 @@ #include "Spider.h" - +#include "../World.h" +#include "../Entities/Player.h" @@ -33,3 +34,42 @@ void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer) + +void cSpider::EventSeePlayer(cEntity * a_Entity) +{ + if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ())) + { + GetWorld()->QueueLightChunk(GetChunkX(), GetChunkZ()); + return; + } + + if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative() && (GetWorld()->GetBlockBlockLight(this->GetPosition()) <= 9)) + { + super::EventSeePlayer(a_Entity); + } +} + + + + + +bool cSpider::DoTakeDamage(TakeDamageInfo & a_TDI) +{ + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } + + // If the source of the damage is not from an pawn entity, switch to idle + if ((a_TDI.Attacker == nullptr) || !a_TDI.Attacker->IsPawn()) + { + m_EMState = IDLE; + } + else + { + // If the source of the damage is from a pawn entity, chase that entity + m_EMState = CHASING; + } + + return true; +} diff --git a/src/Mobs/Spider.h b/src/Mobs/Spider.h index 24134c00f..4f9df7887 100644 --- a/src/Mobs/Spider.h +++ b/src/Mobs/Spider.h @@ -18,6 +18,8 @@ public: CLASS_PROTODEF(cSpider) virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; + virtual void EventSeePlayer(cEntity *) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; } ; diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp index e4953d546..9239575d0 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -41,7 +41,7 @@ bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) if (a_TDI.DamageType == dtLightning) { Destroy(); - m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtWitch); + m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtWitch, false); return true; } return true; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index dc602ec6c..098c62a90 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -2637,6 +2637,10 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) a_Item.m_Lore = Lore; } + else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) + { + a_Item.m_ItemColor.m_Color = static_cast<unsigned int>(NBT.GetInt(displaytag)); + } } } else if ((TagName == "Fireworks") || (TagName == "Explosion")) @@ -2723,7 +2727,7 @@ void cProtocol172::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) a_Pkt.WriteBEInt8(a_Item.m_ItemCount); a_Pkt.WriteBEInt16(a_Item.m_ItemDamage); - if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR)) + if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid()) { a_Pkt.WriteBEInt16(-1); return; @@ -2740,9 +2744,15 @@ void cProtocol172::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); } - if (!a_Item.IsBothNameAndLoreEmpty()) + if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid()) { Writer.BeginCompound("display"); + + if (a_Item.m_ItemColor.IsValid()) + { + Writer.AddInt("color", static_cast<int>(a_Item.m_ItemColor.m_Color)); + } + if (!a_Item.IsCustomNameEmpty()) { Writer.AddString("Name", a_Item.m_CustomName.c_str()); @@ -3006,6 +3016,19 @@ void cProtocol172::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_En void cProtocol172::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) { + // Living Enitiy Metadata + if (a_Mob.HasCustomName()) + { + a_Pkt.WriteBEUInt8(0x8a); + a_Pkt.WriteString(a_Mob.GetCustomName()); + + a_Pkt.WriteBEUInt8(0x0b); + a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible()); + } + + a_Pkt.WriteBEUInt8(0x66); + a_Pkt.WriteBEFloat(a_Mob.GetHealth()); + switch (a_Mob.GetMobType()) { case mtBat: @@ -3199,15 +3222,6 @@ void cProtocol172::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) break; } } // switch (a_Mob.GetType()) - - // Custom name: - if (a_Mob.HasCustomName()) - { - a_Pkt.WriteBEUInt8(0x8a); - a_Pkt.WriteString(a_Mob.GetCustomName()); - a_Pkt.WriteBEUInt8(0x0b); - a_Pkt.WriteBEUInt8(a_Mob.IsCustomNameAlwaysVisible() ? 1 : 0); - } } diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index db510825e..e8acf8bd4 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -2869,6 +2869,10 @@ void cProtocol180::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) a_Item.m_Lore = Lore; } + else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) + { + a_Item.m_ItemColor.m_Color = static_cast<unsigned int>(NBT.GetInt(displaytag)); + } } } else if ((TagName == "Fireworks") || (TagName == "Explosion")) @@ -3018,12 +3022,13 @@ void cProtocol180::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) a_Pkt.WriteBEInt8(a_Item.m_ItemCount); a_Pkt.WriteBEInt16(a_Item.m_ItemDamage); - if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR)) + if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR) && !a_Item.m_ItemColor.IsValid()) { a_Pkt.WriteBEInt8(0); return; } + // Send the enchantments and custom names: cFastNBTWriter Writer; if (a_Item.m_RepairCost != 0) @@ -3035,9 +3040,14 @@ void cProtocol180::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); } - if (!a_Item.IsBothNameAndLoreEmpty()) + if (!a_Item.IsBothNameAndLoreEmpty() || a_Item.m_ItemColor.IsValid()) { Writer.BeginCompound("display"); + if (a_Item.m_ItemColor.IsValid()) + { + Writer.AddInt("color", static_cast<int>(a_Item.m_ItemColor.m_Color)); + } + if (!a_Item.IsCustomNameEmpty()) { Writer.AddString("Name", a_Item.m_CustomName.c_str()); @@ -3197,7 +3207,7 @@ void cProtocol180::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_En } a_Pkt.WriteBEUInt8(0); // Byte(0) + index 0 a_Pkt.WriteBEUInt8(Flags); - + switch (a_Entity.GetEntityType()) { case cEntity::etPlayer: break; // TODO? @@ -3303,6 +3313,19 @@ void cProtocol180::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_En void cProtocol180::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) { + // Living Enitiy Metadata + if (a_Mob.HasCustomName()) + { + a_Pkt.WriteBEUInt8(0x82); + a_Pkt.WriteString(a_Mob.GetCustomName()); + + a_Pkt.WriteBEUInt8(0x03); + a_Pkt.WriteBool(a_Mob.IsCustomNameAlwaysVisible()); + } + + a_Pkt.WriteBEUInt8(0x66); + a_Pkt.WriteBEFloat(a_Mob.GetHealth()); + switch (a_Mob.GetMobType()) { case mtBat: @@ -3414,14 +3437,6 @@ void cProtocol180::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) break; } // case mtPig - case mtRabbit: - { - auto & Rabbit = reinterpret_cast<const cRabbit &>(a_Mob); - a_Pkt.WriteBEUInt8(0x0c); - a_Pkt.WriteBEInt8(Rabbit.GetAge()); - break; - } // case mtRabbit - case mtSheep: { auto & Sheep = reinterpret_cast<const cSheep &>(a_Mob); @@ -3439,6 +3454,17 @@ void cProtocol180::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) break; } // case mtSheep + case mtRabbit: + { + auto & Rabbit = reinterpret_cast<const cRabbit &>(a_Mob); + a_Pkt.WriteBEUInt8(0x12); + a_Pkt.WriteBEUInt8(Rabbit.GetRabbitTypeAsNumber()); + + a_Pkt.WriteBEUInt8(0x0c); + a_Pkt.WriteBEInt8(Rabbit.GetAge()); + break; + } // case mtRabbit + case mtSkeleton: { auto & Skeleton = reinterpret_cast<const cSkeleton &>(a_Mob); diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 69c46f090..1e56f9528 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -111,9 +111,12 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re // If source creation is on, check for it here: if ( - (m_NumNeighborsForSource > 0) && // Source creation is on - (MyMeta == m_Falloff) && // Only exactly one block away from a source (fast bail-out) - !IsPassableForFluid(Below) && // Only exactly 1 block deep + (m_NumNeighborsForSource > 0) && // Source creation is on + (MyMeta == m_Falloff) && // Only exactly one block away from a source (fast bail-out) + ( + !IsPassableForFluid(Below) || // Only exactly 1 block deep + (Below == m_StationaryFluidBlock) // Or a source block underneath + ) && CheckNeighborsForSource(a_Chunk, a_RelX, a_RelY, a_RelZ) // Did we create a source? ) { diff --git a/src/World.cpp b/src/World.cpp index dec335253..b152d119a 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3326,7 +3326,7 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) -UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) +UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby) { cMonster * Monster = nullptr; @@ -3337,6 +3337,11 @@ UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterTyp } Monster->SetPosition(a_PosX, a_PosY, a_PosZ); + if (a_Baby) + { + Monster->SetAge(-1); + } + return SpawnMobFinalize(Monster); } diff --git a/src/World.h b/src/World.h index aeab7bfa5..ab2b197c5 100644 --- a/src/World.h +++ b/src/World.h @@ -484,6 +484,7 @@ public: BLOCKTYPE GetBlock (const Vector3i & a_Pos) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z); } NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z); } void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData); } + NIBBLETYPE GetBlockBlockLight(const Vector3i & a_Pos) { return GetBlockBlockLight( a_Pos.x, a_Pos.y, a_Pos.z); } // tolua_end /** Writes the block area into the specified coords. @@ -842,7 +843,7 @@ public: bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */ - virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) override; // tolua_export + virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby = false) override; // tolua_export UInt32 SpawnMobFinalize(cMonster * a_Monster); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 234c60d62..cfbbcd0b4 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -528,113 +528,118 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) { case mtBat: { - m_Writer.AddByte("BatFlags", ((const cBat *)a_Monster)->IsHanging()); + m_Writer.AddByte("BatFlags", reinterpret_cast<const cBat *>(a_Monster)->IsHanging()); break; } case mtCreeper: { - m_Writer.AddByte("powered", ((const cCreeper *)a_Monster)->IsCharged()); - m_Writer.AddByte("ignited", ((const cCreeper *)a_Monster)->IsBlowing()); + const cCreeper *Creeper = reinterpret_cast<const cCreeper *>(a_Monster); + m_Writer.AddByte("powered", Creeper->IsCharged()); + m_Writer.AddByte("ignited", Creeper->IsBlowing()); break; } case mtEnderman: { - m_Writer.AddShort("carried", (Int16)((const cEnderman *)a_Monster)->GetCarriedBlock()); - m_Writer.AddShort("carriedData", (Int16)((const cEnderman *)a_Monster)->GetCarriedMeta()); + const cEnderman *Enderman = reinterpret_cast<const cEnderman *>(a_Monster); + m_Writer.AddShort("carried", (Int16) Enderman->GetCarriedBlock()); + m_Writer.AddShort("carriedData", (Int16) Enderman->GetCarriedMeta()); break; } case mtHorse: { - const cHorse & Horse = *((const cHorse *)a_Monster); - m_Writer.AddByte("ChestedHorse", Horse.IsChested()); - m_Writer.AddByte("EatingHaystack", Horse.IsEating()); - m_Writer.AddByte("Tame", Horse.IsTame()); - m_Writer.AddInt ("Type", Horse.GetHorseType()); - m_Writer.AddInt ("Color", Horse.GetHorseColor()); - m_Writer.AddInt ("Style", Horse.GetHorseStyle()); - m_Writer.AddInt ("ArmorType", Horse.GetHorseArmour()); - m_Writer.AddByte("Saddle", Horse.IsSaddled()); - m_Writer.AddByte("Age", Horse.GetAge()); + const cHorse *Horse = reinterpret_cast<const cHorse *>(a_Monster); + m_Writer.AddByte("ChestedHorse", Horse->IsChested()); + m_Writer.AddByte("EatingHaystack", Horse->IsEating()); + m_Writer.AddByte("Tame", Horse->IsTame()); + m_Writer.AddInt ("Type", Horse->GetHorseType()); + m_Writer.AddInt ("Color", Horse->GetHorseColor()); + m_Writer.AddInt ("Style", Horse->GetHorseStyle()); + m_Writer.AddInt ("ArmorType", Horse->GetHorseArmour()); + m_Writer.AddByte("Saddle", Horse->IsSaddled()); + m_Writer.AddByte("Age", Horse->GetAge()); break; } case mtMagmaCube: { - m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize()); + m_Writer.AddInt("Size", reinterpret_cast<const cMagmaCube *>(a_Monster)->GetSize()); break; } case mtSheep: { - m_Writer.AddByte("Sheared", ((const cSheep *)a_Monster)->IsSheared()); - m_Writer.AddByte("Color", ((const cSheep *)a_Monster)->GetFurColor()); - m_Writer.AddByte("Age", ((const cSheep *)a_Monster)->GetAge()); + const cSheep *Sheep = reinterpret_cast<const cSheep *>(a_Monster); + m_Writer.AddByte("Sheared", Sheep->IsSheared()); + m_Writer.AddByte("Color", Sheep->GetFurColor()); + m_Writer.AddByte("Age", Sheep->GetAge()); break; } case mtSlime: { - m_Writer.AddInt("Size", ((const cSlime *)a_Monster)->GetSize()); + m_Writer.AddInt("Size", reinterpret_cast<const cSlime *>(a_Monster)->GetSize()); break; } case mtSkeleton: { - m_Writer.AddByte("SkeletonType", (((const cSkeleton *)a_Monster)->IsWither() ? 1 : 0)); + m_Writer.AddByte("SkeletonType", (reinterpret_cast<const cSkeleton *>(a_Monster)->IsWither() ? 1 : 0)); break; } case mtVillager: { - m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType()); - m_Writer.AddByte("Age", ((const cVillager *)a_Monster)->GetAge()); + const cVillager *Villager = reinterpret_cast<const cVillager *>(a_Monster); + m_Writer.AddInt("Profession", Villager->GetVilType()); + m_Writer.AddByte("Age", Villager->GetAge()); break; } case mtWither: { - m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks()); + m_Writer.AddInt("Invul", reinterpret_cast<const cWither *>(a_Monster)->GetWitherInvulnerableTicks()); break; } case mtWolf: { - const cWolf & Wolf = *((cWolf *)a_Monster); - if (!Wolf.GetOwnerName().empty()) + const cWolf *Wolf = reinterpret_cast<const cWolf *>(a_Monster); + if (!Wolf->GetOwnerName().empty()) { - m_Writer.AddString("Owner", Wolf.GetOwnerName()); + m_Writer.AddString("Owner", Wolf->GetOwnerName()); } - if (!Wolf.GetOwnerUUID().empty()) + if (!Wolf->GetOwnerUUID().empty()) { - m_Writer.AddString("OwnerUUID", Wolf.GetOwnerUUID()); + m_Writer.AddString("OwnerUUID", Wolf->GetOwnerUUID()); } - m_Writer.AddByte("Sitting", Wolf.IsSitting() ? 1 : 0); - m_Writer.AddByte("Angry", Wolf.IsAngry() ? 1 : 0); - m_Writer.AddByte("CollarColor", (unsigned char)Wolf.GetCollarColor()); - m_Writer.AddByte("Age", Wolf.GetAge()); + m_Writer.AddByte("Sitting", Wolf->IsSitting() ? 1 : 0); + m_Writer.AddByte("Angry", Wolf->IsAngry() ? 1 : 0); + m_Writer.AddByte("CollarColor", (unsigned char) Wolf->GetCollarColor()); + m_Writer.AddByte("Age", Wolf->GetAge()); break; } case mtZombie: { - m_Writer.AddByte("IsVillager", (((const cZombie *)a_Monster)->IsVillagerZombie() ? 1 : 0)); - m_Writer.AddByte("IsConverting", (((const cZombie *)a_Monster)->IsConverting() ? 1 : 0)); - m_Writer.AddByte("Age", (((const cZombie *)a_Monster)->GetAge())); + const cZombie *Zombie = reinterpret_cast<const cZombie *>(a_Monster); + m_Writer.AddByte("IsVillager", Zombie->IsVillagerZombie() ? 1 : 0); + m_Writer.AddByte("IsConverting", Zombie->IsConverting() ? 1 : 0); + m_Writer.AddByte("Age", Zombie->GetAge()); break; } case mtZombiePigman: { - m_Writer.AddByte("Age", (((const cZombiePigman *)a_Monster)->GetAge())); + m_Writer.AddByte("Age", reinterpret_cast<const cZombiePigman *>(a_Monster)->GetAge()); break; } case mtOcelot: { - const cOcelot & Ocelot = *((cOcelot *)a_Monster); - m_Writer.AddByte("Age", Ocelot.GetAge()); + m_Writer.AddByte("Age", reinterpret_cast<const cOcelot *>(a_Monster)->GetAge()); break; } case mtPig: { - const cPig & Pig = *((cPig *)a_Monster); - m_Writer.AddByte("Age", Pig.GetAge()); + m_Writer.AddByte("Age", reinterpret_cast<const cPig *>(a_Monster)->GetAge()); break; } case mtRabbit: { - const cRabbit & Rabbit = *((cRabbit *)a_Monster); - m_Writer.AddByte("Age", Rabbit.GetAge()); + const cRabbit *Rabbit = reinterpret_cast<const cRabbit *>(a_Monster); + m_Writer.AddInt("RabbitType", Rabbit->GetRabbitTypeAsNumber()); + m_Writer.AddInt("MoreCarrotTicks", Rabbit->GetMoreCarrotTicks()); + m_Writer.AddByte("Age", Rabbit->GetAge()); break; } case mtInvalidType: diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 62918f44e..54071b9df 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -2396,7 +2396,18 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB void cWSSAnvil::LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::unique_ptr<cRabbit> Monster = cpp14::make_unique<cRabbit>(); + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "RabbitType"); + int MoreCarrotTicksIdx = a_NBT.FindChildByName(a_TagIdx, "MoreCarrotTicks"); + + if ((TypeIdx < 0) || (MoreCarrotTicksIdx < 0)) + { + return; + } + + int Type = a_NBT.GetInt(TypeIdx); + int MoreCarrotTicks = a_NBT.GetInt(MoreCarrotTicksIdx); + + std::unique_ptr<cRabbit> Monster = cpp14::make_unique<cRabbit>(static_cast<eRabbitType>(Type), MoreCarrotTicks); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; |