diff options
Diffstat (limited to 'src/Items')
-rw-r--r-- | src/Items/ItemDye.h | 194 |
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 + } } ; |