diff options
Diffstat (limited to '')
-rw-r--r-- | src/BlockEntities/DispenserEntity.cpp | 89 | ||||
-rw-r--r-- | src/BlockEntities/DispenserEntity.h | 2 | ||||
-rw-r--r-- | src/Chunk.cpp | 19 | ||||
-rw-r--r-- | src/Chunk.h | 12 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 15 | ||||
-rw-r--r-- | src/ChunkMap.h | 12 | ||||
-rw-r--r-- | src/Defines.h | 13 | ||||
-rw-r--r-- | src/World.cpp | 131 | ||||
-rw-r--r-- | src/World.h | 16 |
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); |