From 672bb0457012612ef59502b33717ee789c4d6bfe Mon Sep 17 00:00:00 2001 From: 0ddlyoko Date: Fri, 6 Nov 2020 17:54:01 +0100 Subject: Add correct implementation of crops (#4802) * [FIX] Add correct implementation of seed drops. > Official percentage of drops has been implemented * Fix C++ conventions * Change "Vals" variable to "m_Vals" * [FIX] Add correct implementation of Carrots, Potatoes, Wheat & Beetroots seed * Add Fortune support with crops Add fortune support with Wheat, Carrots, Potatoes & Beetroots seeds * [FIX] Right-clicking on a grown Beetroot in survival consume 2 bone meals Fix #4805 * Add documentation for "cWorld::IsFullGrownPlantAt" method * Fix dispenser that full grown a plant > Change methods cItemDyeHandler::FertilizePlant & cItemDyeHandler::growPlantsAround to static * Display particle even if tree doesn't grow * When right-clicking on a full grown melon / pumpkin seed, no longer produce a melon / pumpkin Before this commit, when you right-click on a melon or a pumpkin seed, a melon / pumpkin block spawned. With this commit, it no longer spawns * [FIX] Do not create melon / pumpkin block when right-clicking with a bone meal This fix will prevent the creation of a melon / pumpkin block when you right-click with a bone meal on a melon / pumpkin plant - It just detect if the plant is full grown. if yes, the method "Grow" is not called - Remove IsFullGrownPlant Co-authored-by: 12xx12 <12xx12100@gmail.com> Co-authored-by: Tiger Wang --- src/BlockEntities/DispenserEntity.cpp | 79 ++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 38 deletions(-) (limited to 'src/BlockEntities') diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index d97d7198e..c2ce6cf7c 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -10,6 +10,7 @@ #include "../Entities/ProjectileEntity.h" #include "../Simulator/FluidSimulator.h" #include "../Items/ItemSpawnEgg.h" +#include "../Items/ItemDye.h" @@ -25,24 +26,24 @@ cDispenserEntity::cDispenserEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { - Vector3i dispRelCoord(GetRelPos()); - auto meta = a_Chunk.GetMeta(dispRelCoord); - AddDropSpenserDir(dispRelCoord, meta); - auto dispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(dispRelCoord); - if (dispChunk == nullptr) + Vector3i DispRelCoord(GetRelPos()); + auto Meta = a_Chunk.GetMeta(DispRelCoord); + AddDropSpenserDir(DispRelCoord, Meta); + auto DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispRelCoord); + if (DispChunk == nullptr) { // Would dispense into / interact with a non-loaded chunk, ignore the tick return; } - BLOCKTYPE dispBlock = dispChunk->GetBlock(dispRelCoord); - auto dispAbsCoord = dispChunk->RelativeToAbsolute(dispRelCoord); + BLOCKTYPE DispBlock = DispChunk->GetBlock(DispRelCoord); + auto DispAbsCoord = DispChunk->RelativeToAbsolute(DispRelCoord); // Dispense the item: 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 (ItemCategory::IsMinecart(SlotItem.m_ItemType) && IsBlockRail(DispBlock)) // only actually place the minecart if there are rails! { - if (m_World->SpawnMinecart(dispAbsCoord.x + 0.5, dispAbsCoord.y + 0.5, dispAbsCoord.z + 0.5, SlotItem.m_ItemType) != cEntity::INVALID_ID) + if (m_World->SpawnMinecart(DispAbsCoord.x + 0.5, DispAbsCoord.y + 0.5, DispAbsCoord.z + 0.5, SlotItem.m_ItemType) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -52,15 +53,15 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { case E_ITEM_BUCKET: { - LOGD("Dispensing empty bucket in slot %d; dispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(dispBlock).c_str(), dispBlock); - switch (dispBlock) + LOGD("Dispensing empty bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); + switch (DispBlock) { case E_BLOCK_STATIONARY_WATER: case E_BLOCK_WATER: { if (ScoopUpLiquid(a_SlotNum, E_ITEM_WATER_BUCKET)) { - dispChunk->SetBlock(dispRelCoord, E_BLOCK_AIR, 0); + DispChunk->SetBlock(DispRelCoord, E_BLOCK_AIR, 0); } break; } @@ -69,7 +70,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) { if (ScoopUpLiquid(a_SlotNum, E_ITEM_LAVA_BUCKET)) { - dispChunk->SetBlock(dispRelCoord, E_BLOCK_AIR, 0); + DispChunk->SetBlock(DispRelCoord, E_BLOCK_AIR, 0); } break; } @@ -84,10 +85,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_WATER_BUCKET: { - LOGD("Dispensing water bucket in slot %d; dispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(dispBlock).c_str(), dispBlock); - if (EmptyLiquidBucket(dispBlock, a_SlotNum)) + LOGD("Dispensing water bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); + if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { - dispChunk->SetBlock(dispRelCoord, E_BLOCK_WATER, 0); + DispChunk->SetBlock(DispRelCoord, E_BLOCK_WATER, 0); } else { @@ -98,10 +99,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_LAVA_BUCKET: { - LOGD("Dispensing lava bucket in slot %d; dispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(dispBlock).c_str(), dispBlock); - if (EmptyLiquidBucket(dispBlock, a_SlotNum)) + LOGD("Dispensing lava bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock); + if (EmptyLiquidBucket(DispBlock, a_SlotNum)) { - dispChunk->SetBlock(dispRelCoord, E_BLOCK_LAVA, 0); + DispChunk->SetBlock(DispRelCoord, E_BLOCK_LAVA, 0); } else { @@ -112,10 +113,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SPAWN_EGG: { - double MobX = 0.5 + dispAbsCoord.x; - double MobZ = 0.5 + dispAbsCoord.z; + double MobX = 0.5 + DispAbsCoord.x; + double MobZ = 0.5 + DispAbsCoord.z; auto MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(m_Contents.GetSlot(a_SlotNum).m_ItemDamage); - if (m_World->SpawnMob(MobX, dispAbsCoord.y, MobZ, MonsterType, false) != cEntity::INVALID_ID) + if (m_World->SpawnMob(MobX, DispAbsCoord.y, MobZ, MonsterType, false) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -125,9 +126,9 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_BLOCK_TNT: { // Spawn a primed TNT entity, if space allows: - if (!cBlockInfo::IsSolid(dispBlock)) + if (!cBlockInfo::IsSolid(DispBlock)) { - m_World->SpawnPrimedTNT(Vector3d(0.5, 0.5, 0.5) + dispAbsCoord, 80, 0); // 80 ticks fuse, no initial velocity + m_World->SpawnPrimedTNT(Vector3d(0.5, 0.5, 0.5) + DispAbsCoord, 80, 0); // 80 ticks fuse, no initial velocity m_Contents.ChangeSlotCount(a_SlotNum, -1); } break; @@ -136,9 +137,9 @@ 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 (dispBlock == E_BLOCK_AIR) + if (DispBlock == E_BLOCK_AIR) { - dispChunk->SetBlock(dispRelCoord, E_BLOCK_FIRE, 0); + DispChunk->SetBlock(DispRelCoord, E_BLOCK_FIRE, 0); bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1); @@ -152,7 +153,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIRE_CHARGE: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkFireCharge, GetShootVector(meta) * 20) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -161,7 +162,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ARROW: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkArrow, GetShootVector(meta) * 30 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkArrow, GetShootVector(Meta) * 30 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -170,7 +171,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_SNOWBALL: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkSnowball, GetShootVector(meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -179,7 +180,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_EGG: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkEgg, GetShootVector(meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -188,7 +189,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_BOTTLE_O_ENCHANTING: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkExpBottle, GetShootVector(meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkExpBottle, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0)) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -197,7 +198,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_POTION: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkSplashPotion, GetShootVector(meta) * 20 + Vector3d(0, 1, 0), &SlotItem) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkSplashPotion, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0), &SlotItem) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -211,7 +212,9 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) DropFromSlot(a_Chunk, a_SlotNum); break; } - if (m_World->GrowRipePlant(dispAbsCoord.x, dispAbsCoord.y, dispAbsCoord.z, true)) + + // Simulate a right-click with bonemeal: + if (cItemDyeHandler::FertilizePlant(*m_World, DispAbsCoord)) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } @@ -225,13 +228,13 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_ACACIA_BOAT: case E_ITEM_DARK_OAK_BOAT: { - Vector3d spawnPos = dispAbsCoord; - if (IsBlockWater(dispBlock)) + Vector3d spawnPos = DispAbsCoord; + if (IsBlockWater(DispBlock)) { // Water next to the dispenser, spawn a boat above the water block spawnPos.y += 1; } - else if (IsBlockWater(dispChunk->GetBlock(dispRelCoord.addedY(-1)))) + else if (IsBlockWater(DispChunk->GetBlock(DispRelCoord.addedY(-1)))) { // Water one block below the dispenser, spawn a boat at the dispenser's Y level // No adjustment needed @@ -243,7 +246,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int 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 += 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, cBoat::ItemToMaterial(SlotItem))) @@ -255,7 +258,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) case E_ITEM_FIREWORK_ROCKET: { - if (SpawnProjectileFromDispenser(dispAbsCoord, cProjectileEntity::pkFirework, GetShootVector(meta) * 20 + Vector3d(0, 1, 0), &SlotItem) != cEntity::INVALID_ID) + if (SpawnProjectileFromDispenser(DispAbsCoord, cProjectileEntity::pkFirework, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0), &SlotItem) != cEntity::INVALID_ID) { m_Contents.ChangeSlotCount(a_SlotNum, -1); } -- cgit v1.2.3