summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua5
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/crafting.txt38
-rw-r--r--src/BlockEntities/DispenserEntity.cpp2
-rw-r--r--src/Blocks/BlockPortal.h2
-rw-r--r--src/Blocks/WorldInterface.h2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Color.cpp76
-rw-r--r--src/Color.h58
-rw-r--r--src/CraftingRecipes.cpp192
-rw-r--r--src/CraftingRecipes.h3
-rw-r--r--src/Entities/ThrownEggEntity.cpp10
-rw-r--r--src/Generating/Trees.h1
-rw-r--r--src/Item.cpp19
-rw-r--r--src/Item.h11
-rw-r--r--src/Items/ItemMobHead.h2
-rw-r--r--src/Items/ItemPumpkin.h4
-rw-r--r--src/Items/ItemSpawnEgg.h2
-rw-r--r--src/Mobs/Monster.h2
-rw-r--r--src/Mobs/Mooshroom.cpp2
-rw-r--r--src/Mobs/Pig.cpp2
-rw-r--r--src/Mobs/Rabbit.cpp15
-rw-r--r--src/Mobs/Rabbit.h25
-rw-r--r--src/Mobs/Spider.cpp42
-rw-r--r--src/Mobs/Spider.h2
-rw-r--r--src/Mobs/Villager.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp36
-rw-r--r--src/Protocol/Protocol18x.cpp48
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp9
-rw-r--r--src/World.cpp7
-rw-r--r--src/World.h3
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp91
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp13
33 files changed, 635 insertions, 92 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 09479ee4e..0476c4a93 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1751,6 +1751,9 @@ a_Player:OpenWindow(Window);
StringToMobType = { Params = "string", Return = "{{Globals#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{Globals#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." },
GetRelativeWalkSpeed = { Params = "", Return = "number", Notes = "Returns the relative walk speed of this mob. Standard is 1.0" },
SetRelativeWalkSpeed = { Params = "number", Return = "", Notes = "Sets the relative walk speed of this mob. Standard is 1.0" },
+ SetAge = { Params = "number", Return = "", Notes = "Sets the age of the monster" },
+ GetAge = { Params = "", Return = "number", Notes = "Returns the age of the monster" },
+ IsBaby = { Params = "", Return = "bool", Notes = "Returns true if the monster is a baby" },
},
Constants =
{
@@ -2473,7 +2476,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
{ Params = "{{cItems|Pickups}}, X, Y, Z, SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Spawns the specified pickups at the position specified. All the pickups fly away from the spawn position using the specified speed." },
},
SpawnMinecart = { Params = "X, Y, Z, MinecartType, Item, BlockHeight", Return = "number", Notes = "Spawns a minecart at the specific coordinates. MinecartType is the item type of the minecart. If the minecart is an empty minecart then the given item is the block inside the minecart, and blockheight is the distance of the block and the minecart." },
- SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " },
+ SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}, [Baby]", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. If the Baby parameter is true, the mob will be a baby. Returns the EntityID of the creates entity, or -1 on failure. " },
SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" },
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject cbf3280a6a3cbf9468742dbbdaca9ff6f0a7743
+Subproject ee01115ac848116cf58956fa6d031dbbadddba0
diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt
index b08a82f2f..8adc00fa2 100644
--- a/MCServer/crafting.txt
+++ b/MCServer/crafting.txt
@@ -552,6 +552,44 @@ GlisteringMelon = MelonSlice, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1
GoldNugget, 9 = GoldIngot, *
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
+#******************************************************#
+# Dyed Armor
+# Do not modify
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherHelmet = LeatherHelmet^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherChestplate = LeatherChestplate^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+
+LeatherPants = LeatherPants^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherPants = LeatherPants^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
+LeatherBoots = LeatherBoots^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, * | Dye^-1, *
#******************************************************#
# Fireworks & Co.
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;