summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/BlockEntities/DispenserEntity.cpp89
-rw-r--r--src/BlockEntities/DispenserEntity.h2
-rw-r--r--src/Chunk.cpp19
-rw-r--r--src/Chunk.h12
-rw-r--r--src/ChunkMap.cpp15
-rw-r--r--src/ChunkMap.h12
-rw-r--r--src/Defines.h13
-rw-r--r--src/World.cpp131
-rw-r--r--src/World.h16
9 files changed, 206 insertions, 103 deletions
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index 297d5273e..e03644a0f 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -3,8 +3,10 @@
#include "DispenserEntity.h"
#include "../Simulator/FluidSimulator.h"
+#include "../Entities/Boat.h"
#include "../Chunk.h"
+#include "../Defines.h"
#include "../World.h"
#include "../Entities/ProjectileEntity.h"
@@ -39,7 +41,16 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
// Dispense the item:
- switch (m_Contents.GetSlot(a_SlotNum).m_ItemType)
+ const cItem & SlotItem = m_Contents.GetSlot(a_SlotNum);
+ if (ItemCategory::IsMinecart(SlotItem.m_ItemType) && IsBlockRail(DispBlock)) // only actually place the minecart if there are rails!
+ {
+ if (m_World->SpawnMinecart(BlockX + 0.5, DispY + 0.5, BlockZ + 0.5, SlotItem.m_ItemType) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
+ return;
+ }
+ switch (SlotItem.m_ItemType)
{
case E_ITEM_BUCKET:
{
@@ -115,7 +126,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
case E_BLOCK_TNT:
{
// Spawn a primed TNT entity, if space allows:
- if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
+ if (!cBlockInfo::IsSolid(DispBlock))
{
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
@@ -128,7 +139,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
case E_ITEM_FLINT_AND_STEEL:
{
// Spawn fire if the block in front is air.
- if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
+ if (DispBlock == E_BLOCK_AIR)
{
DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0);
@@ -153,7 +164,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
case E_ITEM_ARROW:
{
- if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 30 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
{
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
@@ -178,6 +189,68 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break;
}
+ case E_ITEM_BOTTLE_O_ENCHANTING:
+ {
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkExpBottle, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
+ break;
+ }
+
+ case E_ITEM_POTION:
+ {
+ if (SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSplashPotion, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0), &SlotItem) != cEntity::INVALID_ID)
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
+ break;
+ }
+
+ case E_ITEM_DYE:
+ {
+ if (SlotItem.m_ItemDamage != E_META_DYE_WHITE)
+ {
+ DropFromSlot(a_Chunk, a_SlotNum);
+ break;
+ }
+ if (m_World->GrowRipePlant(BlockX, DispY, BlockZ, true))
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
+ break;
+ }
+
+ case E_ITEM_BOAT:
+ {
+ Vector3d SpawnPos;
+ if (IsBlockWater(DispBlock))
+ {
+ // Water next to the dispenser, spawn a boat above the water block
+ SpawnPos.Set(BlockX, DispY + 1, BlockZ);
+ }
+ else if (IsBlockWater(DispChunk->GetBlock(DispX, DispY - 1, DispZ)))
+ {
+ // Water one block below the dispenser, spawn a boat at the dispenser's Y level
+ SpawnPos.Set(BlockX, DispY, BlockZ);
+ }
+ else
+ {
+ // There's no eligible water block, drop the boat as a pickup
+ DropFromSlot(a_Chunk, a_SlotNum);
+ break;
+ }
+
+ SpawnPos += GetShootVector(Meta) * 0.8; // A boat is bigger than one block. Add the shoot vector to put it outside the dispenser.
+ SpawnPos += Vector3d(0.5, 0.5, 0.5);
+
+ if (m_World->SpawnBoat(SpawnPos.x, SpawnPos.y, SpawnPos.z))
+ {
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ }
+ break;
+ }
+
case E_ITEM_FIREWORK_ROCKET:
{
// TODO: Add the fireworks entity
@@ -189,27 +262,25 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
DropFromSlot(a_Chunk, a_SlotNum);
break;
}
- } // switch (ItemType)
+ } // switch (SlotItem.m_ItemType)
}
-UInt32 cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector)
+UInt32 cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector, const cItem * a_Item)
{
return m_World->CreateProjectile(
static_cast<double>(a_BlockX + 0.5),
static_cast<double>(a_BlockY + 0.5),
static_cast<double>(a_BlockZ + 0.5),
- a_Kind, nullptr, nullptr, &a_ShootVector
+ a_Kind, nullptr, a_Item, &a_ShootVector
);
}
-
-
Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x7)
diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h
index c9b553017..03ce3ad69 100644
--- a/src/BlockEntities/DispenserEntity.h
+++ b/src/BlockEntities/DispenserEntity.h
@@ -26,7 +26,7 @@ public:
/** Spawns a projectile of the given kind in front of the dispenser with the specified speed.
Returns the UniqueID of the spawned projectile, or 0 on failure. */
- UInt32 SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed);
+ UInt32 SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed, const cItem * a_Item = nullptr);
/** Returns a unit vector in the cardinal direction of where the dispenser is facing. */
Vector3d GetShootVector(NIBBLETYPE a_Meta);
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 363de9933..c65c043da 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -929,7 +929,7 @@ void cChunk::ApplyWeatherToTop()
-void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_TickRandom)
+bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_TickRandom)
{
// Convert the stem BlockType into produce BlockType
BLOCKTYPE ProduceType;
@@ -940,7 +940,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
default:
{
ASSERT(!"Unhandled blocktype in TickMelonPumpkin()");
- return;
+ return false;
}
}
@@ -961,7 +961,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
)
{
// Neighbors not valid or already taken by the same produce
- return;
+ return false;
}
// Pick a direction in which to place the produce:
@@ -985,7 +985,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
{
break;
}
- default: return;
+ default: return false;
}
// Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok
@@ -1013,13 +1013,14 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
break;
}
}
+ return true;
}
-void cChunk::GrowSugarcane(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
+int cChunk::GrowSugarcane(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
{
// Check the total height of the sugarcane blocks here:
int Top = a_RelY + 1;
@@ -1051,16 +1052,17 @@ void cChunk::GrowSugarcane(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
}
else
{
- break;
+ return i;
}
} // for i
+ return ToGrow;
}
-void cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
+int cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
{
// Check the total height of the sugarcane blocks here:
int Top = a_RelY + 1;
@@ -1093,9 +1095,10 @@ void cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
}
else
{
- break;
+ return i;
}
} // for i
+ return ToGrow;
}
diff --git a/src/Chunk.h b/src/Chunk.h
index c7987723b..f8bd9075d 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -580,14 +580,14 @@ private:
/** Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes */
void ApplyWeatherToTop(void);
- /** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */
- void GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
+ /** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking); returns the amount of blocks the sugarcane grew inside this call */
+ int GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
- /** Grows cactus by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */
- void GrowCactus (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
+ /** Grows cactus by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking); returns the amount of blocks the cactus grew inside this call */
+ int GrowCactus (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
- /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */
- void GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_Random);
+ /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem); returns true if the pumpkin or melon sucessfully grew */
+ bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_Random);
/** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */
void MoveEntityToNewChunk(cEntity * a_Entity);
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 83c1c12dd..be22244ad 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -2597,7 +2597,7 @@ void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty)
-void cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, MTRand & a_Rand)
+bool cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, MTRand & a_Rand)
{
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
@@ -2606,15 +2606,16 @@ void cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ);
if (Chunk != nullptr)
{
- Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand);
+ return Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand);
}
+ return false;
}
-void cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
+int cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
{
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
@@ -2623,15 +2624,16 @@ void cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Nu
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ);
if (Chunk != nullptr)
{
- Chunk->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
+ return Chunk->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
}
+ return 0;
}
-void cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
+int cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
{
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
@@ -2640,8 +2642,9 @@ void cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBl
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ);
if (Chunk != nullptr)
{
- Chunk->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
+ return Chunk->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
}
+ return 0;
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index bbde06dcf..b481e3c9b 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -360,14 +360,14 @@ public:
/** Returns the number of valid chunks and the number of dirty chunks */
void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty);
- /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */
- void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, MTRand & a_Rand);
+ /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem); returns true if the pumpkin or melon sucessfully grew */
+ bool GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, MTRand & a_Rand);
- /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config */
- void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+ /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config; returns the amount of blocks the sugarcane grew inside this call */
+ int GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
- /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config */
- void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+ /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config; returns the amount of blocks the cactus grew inside this call */
+ int GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
/** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */
void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ);
diff --git a/src/Defines.h b/src/Defines.h
index 37b80cca3..13049ce4f 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -788,6 +788,19 @@ namespace ItemCategory
+ inline bool IsMinecart(short a_ItemType)
+ {
+ return (
+ (a_ItemType == E_ITEM_MINECART) ||
+ (a_ItemType == E_ITEM_CHEST_MINECART) ||
+ (a_ItemType == E_ITEM_FURNACE_MINECART) ||
+ (a_ItemType == E_ITEM_MINECART_WITH_TNT) ||
+ (a_ItemType == E_ITEM_MINECART_WITH_HOPPER)
+ );
+ }
+
+
+
inline bool IsArmor(short a_ItemType)
{
return (
diff --git a/src/World.cpp b/src/World.cpp
index d05f90365..55079250c 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -17,6 +17,7 @@
#include "WorldStorage/ScoreboardSerializer.h"
// Entities (except mobs):
+#include "Entities/Boat.h"
#include "Entities/ExpOrb.h"
#include "Entities/FallingBlock.h"
#include "Entities/Minecart.h"
@@ -1705,25 +1706,22 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
{
case E_BLOCK_CARROTS:
{
- if (a_IsByBonemeal && !m_IsCarrotsBonemealable)
+ if ((a_IsByBonemeal && !m_IsCarrotsBonemealable) || (BlockMeta >= 7))
{
return false;
}
- if (BlockMeta < 7)
+ if (!a_IsByBonemeal)
{
- if (!a_IsByBonemeal)
- {
- ++BlockMeta;
- }
- else
- {
- BlockMeta += random.NextInt(4) + 2;
- BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
- }
- FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ ++BlockMeta;
+ }
+ else
+ {
+ BlockMeta += random.NextInt(4) + 2;
+ BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
}
- return BlockMeta == 7;
+ FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
case E_BLOCK_COCOA_POD:
@@ -1731,36 +1729,34 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
NIBBLETYPE TypeMeta = BlockMeta & 0x03;
int GrowState = BlockMeta >> 2;
- if (GrowState < 2)
+ if (GrowState >= 2)
{
- GrowState++;
- FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, static_cast<NIBBLETYPE>(GrowState << 2 | TypeMeta));
- BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return false;
}
- return GrowState == 2;
+ ++GrowState;
+ FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, static_cast<NIBBLETYPE>(GrowState << 2 | TypeMeta));
+ BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
case E_BLOCK_CROPS:
{
- if (a_IsByBonemeal && !m_IsCropsBonemealable)
+ if ((a_IsByBonemeal && !m_IsCropsBonemealable) || (BlockMeta >= 7))
{
return false;
}
- if (BlockMeta < 7)
+ if (!a_IsByBonemeal)
{
- if (!a_IsByBonemeal)
- {
- ++BlockMeta;
- }
- else
- {
- BlockMeta += random.NextInt(4) + 2;
- BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
- }
- FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ ++BlockMeta;
+ }
+ else
+ {
+ BlockMeta += random.NextInt(4) + 2;
+ BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
}
- return BlockMeta == 7;
+ FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
case E_BLOCK_MELON_STEM:
@@ -1783,6 +1779,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
}
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
else
{
@@ -1790,32 +1787,28 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
{
return false;
}
- GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType);
+ return GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType);
}
- return BlockMeta == 7;
}
case E_BLOCK_POTATOES:
{
- if (a_IsByBonemeal && !m_IsPotatoesBonemealable)
+ if ((a_IsByBonemeal && !m_IsPotatoesBonemealable) || (BlockMeta >= 7))
{
return false;
}
- if (BlockMeta < 7)
+ if (!a_IsByBonemeal)
{
- if (!a_IsByBonemeal)
- {
- ++BlockMeta;
- }
- else
- {
- BlockMeta += random.NextInt(4) + 2;
- BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
- }
- FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ ++BlockMeta;
+ }
+ else
+ {
+ BlockMeta += random.NextInt(4) + 2;
+ BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
}
- return BlockMeta == 7;
+ FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
case E_BLOCK_PUMPKIN_STEM:
@@ -1838,6 +1831,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
}
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
}
else
{
@@ -1845,9 +1839,8 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
{
return false;
}
- GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType);
+ return GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType);
}
- return BlockMeta == 7;
}
case E_BLOCK_SAPLING:
@@ -1930,8 +1923,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
{
return false;
}
- m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, m_MaxSugarcaneHeight);
- return true;
+ return m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, 1) != 0;
}
case E_BLOCK_CACTUS:
@@ -1940,8 +1932,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
{
return false;
}
- m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, m_MaxCactusHeight);
- return true;
+ return m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, 1) != 0;
}
} // switch (BlockType)
return false;
@@ -1951,28 +1942,28 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
-void cWorld::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
+int cWorld::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
{
- m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
+ return m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
}
-void cWorld::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
+bool cWorld::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
{
MTRand Rand;
- m_ChunkMap->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, Rand);
+ return m_ChunkMap->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, Rand);
}
-void cWorld::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
+int cWorld::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow)
{
- m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
+ return m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, a_NumBlocksToGrow);
}
@@ -2181,6 +2172,24 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT
+UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z)
+{
+ cBoat * Boat = new cBoat(a_X, a_Y, a_Z);
+ if (Boat == nullptr)
+ {
+ return cEntity::INVALID_ID;
+ }
+ if (!Boat->Initialize(*this))
+ {
+ delete Boat;
+ return cEntity::INVALID_ID;
+ }
+ return Boat->GetUniqueID();
+}
+
+
+
+
UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
diff --git a/src/World.h b/src/World.h
index eafe7b9b6..2181671ad 100644
--- a/src/World.h
+++ b/src/World.h
@@ -445,6 +445,10 @@ public:
Returns the UniqueID of the spawned minecart, or cEntity::INVALID_ID on failure. */
UInt32 SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
+ /** Spawns a boat at the given coordinates.
+ Returns the UniqueID of the spawned boat, or cEntity::INVALID_ID on failure. */
+ UInt32 SpawnBoat(double a_X, double a_Y, double a_Z);
+
/** 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. */
virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override;
@@ -582,14 +586,14 @@ public:
/** Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini */
bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false);
- /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config */
- void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+ /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config; returns the amount of blocks the cactus grew inside this call */
+ int GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
- /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */
- void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
+ /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem); returns true if the pumpkin or melon sucessfully grew. */
+ bool GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
- /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config */
- void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+ /** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config; returns the amount of blocks the sugarcane grew inside this call */
+ int GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
/** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);