summaryrefslogtreecommitdiffstats
path: root/src/Items
diff options
context:
space:
mode:
Diffstat (limited to 'src/Items')
-rw-r--r--src/Items/ItemDye.h194
1 files changed, 188 insertions, 6 deletions
diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h
index c776d5244..94ee9ed6f 100644
--- a/src/Items/ItemDye.h
+++ b/src/Items/ItemDye.h
@@ -13,26 +13,29 @@
class cItemDyeHandler :
public cItemHandler
{
+ using super = cItemHandler;
+
public:
- cItemDyeHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+ cItemDyeHandler(int a_ItemType):
+ super(a_ItemType)
{
}
+
+
virtual bool OnItemUse(
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
) override
{
- // Handle growing the plants:
if ((a_Item.m_ItemDamage == E_META_DYE_WHITE) && (a_BlockFace != BLOCK_FACE_NONE))
{
- if (a_World->GrowRipePlant(a_BlockX, a_BlockY, a_BlockZ, true))
+ // Bonemeal (white dye) is used to fertilize plants:
+ if (fertilizePlant(*a_World, {a_BlockX, a_BlockY, a_BlockZ}))
{
- // Particle effects are in GrowRipePlant
- if (!a_Player->IsGameModeCreative())
+ if (a_Player->IsGameModeSurvival())
{
a_Player->GetInventory().RemoveOneEquippedItem();
return true;
@@ -41,6 +44,7 @@ public:
}
else if ((a_Item.m_ItemDamage == E_META_DYE_BROWN) && (a_BlockFace >= BLOCK_FACE_ZM) && (a_BlockFace <= BLOCK_FACE_XP))
{
+ // Cocoa (brown dye) can be planted on jungle logs:
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
@@ -73,6 +77,184 @@ public:
return false;
}
+
+
+
+
+ /** Attempts to use the bonemeal on the plant at the specified (absolute) position.
+ The effect of fertilization depends on the plant: https://minecraft.gamepedia.com/Bone_Meal#Fertilizer
+ - grow a few stages
+ - grow 1 stage with a chance
+ - drop pickups without destroying the plant
+ - grow more plants in the vicinity
+ If fertilized succesfully, spawn appropriate particle effects, too.
+ Returns true if the plant was fertilized successfully, false if not / not a plant.
+ Note that successful fertilization doesn't mean successful growth - for blocks that have only a chance to grow,
+ fertilization success is reported even in the case when the chance fails (bonemeal still needs to be consumed). */
+ bool fertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
+ {
+ BLOCKTYPE blockType;
+ NIBBLETYPE blockMeta;
+ if (!a_World.GetBlockTypeMeta(a_BlockPos, blockType, blockMeta))
+ {
+ return false;
+ }
+ switch (blockType)
+ {
+ case E_BLOCK_WHEAT:
+ case E_BLOCK_CARROTS:
+ case E_BLOCK_POTATOES:
+ case E_BLOCK_MELON_STEM:
+ case E_BLOCK_PUMPKIN_STEM:
+ {
+ // Grow by 2 - 5 stages:
+ auto numStages = GetRandomProvider().RandInt(2, 5);
+ if (a_World.GrowPlantAt(a_BlockPos, numStages) <= 0)
+ {
+ return false;
+ }
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockPos, 0);
+ return true;
+ } // case wheat, carrots, potatoes, melon stem, pumpkin stem
+
+ case E_BLOCK_BEETROOTS:
+ {
+ // 75% chance of 1-stage growth:
+ if (GetRandomProvider().RandBool(0.75))
+ {
+ if (a_World.GrowPlantAt(a_BlockPos, 1) > 0)
+ {
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockPos, 0);
+ }
+ }
+ return true;
+ } // case beetroots
+
+ case E_BLOCK_SAPLING:
+ {
+ // 45% chance of growing to the next stage / full tree:
+ if (GetRandomProvider().RandBool(0.45))
+ {
+ if (a_World.GrowPlantAt(a_BlockPos, 1) > 0)
+ {
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockPos, 0);
+ }
+ }
+ return true;
+ }
+
+ case E_BLOCK_BIG_FLOWER:
+ {
+ // Drop the corresponding flower item without destroying the block:
+ cItems pickups;
+ switch (blockMeta)
+ {
+ case E_META_BIG_FLOWER_SUNFLOWER: pickups.Add(E_BLOCK_BIG_FLOWER, 1, E_META_BIG_FLOWER_SUNFLOWER); break;
+ case E_META_BIG_FLOWER_LILAC: pickups.Add(E_BLOCK_BIG_FLOWER, 1, E_META_BIG_FLOWER_LILAC); break;
+ case E_META_BIG_FLOWER_ROSE_BUSH: pickups.Add(E_BLOCK_BIG_FLOWER, 1, E_META_BIG_FLOWER_ROSE_BUSH); break;
+ case E_META_BIG_FLOWER_PEONY: pickups.Add(E_BLOCK_BIG_FLOWER, 1, E_META_BIG_FLOWER_PEONY); break;
+ }
+ // TODO: Should we call any hook for this?
+ a_World.SpawnItemPickups(pickups, a_BlockPos);
+ return true;
+ } // big flower
+
+ case E_BLOCK_TALL_GRASS:
+ case E_BLOCK_COCOA_POD:
+ case E_BLOCK_SUGARCANE:
+ case E_BLOCK_CACTUS:
+ {
+ // Always try to grow 1 stage:
+ if (a_World.GrowPlantAt(a_BlockPos, 1) <= 0)
+ {
+ return false;
+ }
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockPos, 0);
+ return true;
+ } // case tall grass
+
+ case E_BLOCK_RED_MUSHROOM:
+ case E_BLOCK_BROWN_MUSHROOM:
+ {
+ // 40% chance of growing into a large mushroom:
+ if (GetRandomProvider().RandBool(0.6))
+ {
+ return false;
+ }
+ if (a_World.GrowPlantAt(a_BlockPos, 1) <= 0)
+ {
+ return false;
+ }
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockPos, 0);
+ return true;
+ } // case red or brown mushroom
+
+ case E_BLOCK_GRASS:
+ {
+ growPlantsAround(a_World, a_BlockPos);
+ return true;
+ }
+
+ // TODO: case E_BLOCK_SWEET_BERRY_BUSH:
+ // TODO: case E_BLOCK_SEA_PICKLE:
+ // TODO: case E_BLOCK_KELP:
+ // TODO: case E_BLOCK_BAMBOO:
+ } // switch (blockType)
+ return false;
+ }
+
+
+
+
+
+ /** Grows new plants around the specified block.
+ Places up to 40 new plants, with the following probability:
+ - 20 % big grass (2-block tall grass)
+ - 60 % tall grass (1-block tall grass)
+ - 20 % flowers (biome dependent variants)
+ The new plants are spawned within 7 taxicab distance of a_BlockPos, on a grass block.
+ Broadcasts a particle for each new spawned plant. */
+ void growPlantsAround(cWorld & a_World, Vector3i a_BlockPos)
+ {
+ auto & r1 = GetRandomProvider();
+ for (int i = 0; i < 40; ++i)
+ {
+ int ofsY = r1.RandInt(3) + r1.RandInt(3) - 3;
+ if (!cChunkDef::IsValidHeight(a_BlockPos.y + ofsY))
+ {
+ continue;
+ }
+ int ofsX = (r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3)) / 2 - 3;
+ int ofsZ = (r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3)) / 2 - 3;
+ Vector3i ofs(ofsX, ofsY, ofsZ);
+ auto typeGround = a_World.GetBlock(a_BlockPos + ofs);
+ if (typeGround != E_BLOCK_GRASS)
+ {
+ continue;
+ }
+ auto pos = a_BlockPos + ofs.addedY(1);
+ auto typeAbove = a_World.GetBlock(pos);
+ if (typeAbove != E_BLOCK_AIR)
+ {
+ continue;
+ }
+ BLOCKTYPE spawnType;
+ NIBBLETYPE spawnMeta = 0;
+ switch (r1.RandInt(10))
+ {
+ case 0: spawnType = E_BLOCK_YELLOW_FLOWER; break;
+ case 1: spawnType = E_BLOCK_RED_ROSE; break;
+ default:
+ {
+ spawnType = E_BLOCK_TALL_GRASS;
+ spawnMeta = E_META_TALL_GRASS_GRASS;
+ break;
+ }
+ } // switch (random spawn block type)
+ a_World.SetBlock(pos, spawnType, spawnMeta);
+ a_World.BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, pos, 0);
+ } // for i - attempts
+ }
} ;