2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2015-08-19 12:45:53 -04:00
|
|
|
#include "BlockPlant.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-10-11 05:02:53 -04:00
|
|
|
/** Handler for stems from which produce grows in an adjacent block (melon, pumpkin) after it becomes ripe (meta == 7).
|
|
|
|
ProduceBlockType is the blocktype for the produce to be grown.
|
|
|
|
StemPickupType is the item type for the pickup resulting from breaking the stem. */
|
2020-04-03 02:57:01 -04:00
|
|
|
template <BLOCKTYPE ProduceBlockType, ENUM_ITEM_TYPE StemPickupType>
|
2020-10-05 06:27:14 -04:00
|
|
|
class cBlockStemsHandler final :
|
2019-10-16 04:06:34 -04:00
|
|
|
public cBlockPlant<true>
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2020-04-13 12:38:06 -04:00
|
|
|
using Super = cBlockPlant<true>;
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
public:
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
using Super::Super;
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
private:
|
2019-10-16 04:06:34 -04:00
|
|
|
|
2021-03-28 09:41:34 -04:00
|
|
|
virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
/*
|
|
|
|
Use correct percent:
|
|
|
|
https://minecraft.gamepedia.com/Melon_Seeds#Breaking
|
|
|
|
https://minecraft.gamepedia.com/Pumpkin_Seeds#Breaking
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Age > 7 (Impossible)
|
|
|
|
if (a_BlockMeta > 7)
|
|
|
|
{
|
|
|
|
return cItem(StemPickupType);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto Threshold = GetRandomProvider().RandReal<double>(100);
|
|
|
|
double Cumulative = 0;
|
|
|
|
char Count = 0;
|
|
|
|
|
|
|
|
for (; Count < 4; Count++)
|
|
|
|
{
|
|
|
|
Cumulative += m_AgeSeedDropProbability[static_cast<size_t>(a_BlockMeta)][static_cast<size_t>(Count)];
|
|
|
|
if (Cumulative > Threshold)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cItem(StemPickupType, Count);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2019-10-16 04:06:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-05-05 09:25:10 -04:00
|
|
|
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
2021-05-05 09:25:10 -04:00
|
|
|
return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND);
|
2019-10-11 05:02:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
|
|
|
UNUSED(a_Meta);
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-09-20 09:50:52 -04:00
|
|
|
virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) const override
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
const auto OldMeta = a_Chunk.GetMeta(a_RelPos);
|
|
|
|
const auto NewMeta = std::clamp<NIBBLETYPE>(static_cast<NIBBLETYPE>(OldMeta + a_NumStages), 0, 7);
|
|
|
|
a_Chunk.SetMeta(a_RelPos, NewMeta);
|
|
|
|
return NewMeta - OldMeta;
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
2020-11-06 11:54:01 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
virtual void BearFruit(cChunk & a_Chunk, const Vector3i a_StemRelPos) const override
|
2015-06-30 10:50:15 -04:00
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
auto & Random = GetRandomProvider();
|
2019-10-11 05:02:53 -04:00
|
|
|
|
|
|
|
// Check if there's another produce around the stem, if so, abort:
|
2020-11-06 11:54:01 -05:00
|
|
|
static constexpr std::array<Vector3i, 4> NeighborOfs =
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
{
|
|
|
|
{ 1, 0, 0},
|
|
|
|
{-1, 0, 0},
|
|
|
|
{ 0, 0, 1},
|
|
|
|
{ 0, 0, -1},
|
|
|
|
}
|
2019-10-11 05:02:53 -04:00
|
|
|
};
|
2020-11-06 11:54:01 -05:00
|
|
|
|
|
|
|
std::array<BLOCKTYPE, 4> BlockType;
|
2019-10-11 05:02:53 -04:00
|
|
|
if (
|
2020-11-06 11:54:01 -05:00
|
|
|
!a_Chunk.UnboundedRelGetBlockType(a_StemRelPos + NeighborOfs[0], BlockType[0]) ||
|
|
|
|
!a_Chunk.UnboundedRelGetBlockType(a_StemRelPos + NeighborOfs[1], BlockType[1]) ||
|
|
|
|
!a_Chunk.UnboundedRelGetBlockType(a_StemRelPos + NeighborOfs[2], BlockType[2]) ||
|
|
|
|
!a_Chunk.UnboundedRelGetBlockType(a_StemRelPos + NeighborOfs[3], BlockType[3]) ||
|
|
|
|
(BlockType[0] == ProduceBlockType) ||
|
|
|
|
(BlockType[1] == ProduceBlockType) ||
|
|
|
|
(BlockType[2] == ProduceBlockType) ||
|
|
|
|
(BlockType[3] == ProduceBlockType)
|
2019-10-11 05:02:53 -04:00
|
|
|
)
|
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
// Neighbors not valid or already taken by the same produce:
|
|
|
|
return;
|
2019-10-11 05:02:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pick a direction in which to place the produce:
|
|
|
|
int x = 0, z = 0;
|
2020-11-06 11:54:01 -05:00
|
|
|
const auto CheckType = Random.RandInt<size_t>(3); // The index to the neighbors array which should be checked for emptiness
|
|
|
|
switch (CheckType)
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
|
|
|
case 0: x = 1; break;
|
|
|
|
case 1: x = -1; break;
|
|
|
|
case 2: z = 1; break;
|
|
|
|
case 3: z = -1; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the block in that direction is empty:
|
2020-11-06 11:54:01 -05:00
|
|
|
switch (BlockType[CheckType])
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_AIR:
|
|
|
|
case E_BLOCK_SNOW:
|
|
|
|
case E_BLOCK_TALL_GRASS:
|
|
|
|
case E_BLOCK_DEAD_BUSH:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2020-11-06 11:54:01 -05:00
|
|
|
default: return;
|
2019-10-11 05:02:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok
|
2020-11-06 11:54:01 -05:00
|
|
|
BLOCKTYPE SoilType;
|
|
|
|
const auto ProduceRelPos = a_StemRelPos + Vector3i(x, 0, z);
|
|
|
|
VERIFY(a_Chunk.UnboundedRelGetBlockType(ProduceRelPos.addedY(-1), SoilType));
|
|
|
|
|
|
|
|
switch (SoilType)
|
2019-10-11 05:02:53 -04:00
|
|
|
{
|
|
|
|
case E_BLOCK_DIRT:
|
|
|
|
case E_BLOCK_GRASS:
|
|
|
|
case E_BLOCK_FARMLAND:
|
|
|
|
{
|
2020-11-06 11:54:01 -05:00
|
|
|
const NIBBLETYPE Meta = (ProduceBlockType == E_BLOCK_MELON) ? 0 : static_cast<NIBBLETYPE>(Random.RandInt(4) % 4);
|
|
|
|
|
2019-10-11 05:02:53 -04:00
|
|
|
FLOGD("Growing melon / pumpkin at {0} (<{1}, {2}> from stem), overwriting {3}, growing on top of {4}, meta {5}",
|
2020-11-06 11:54:01 -05:00
|
|
|
a_Chunk.RelativeToAbsolute(ProduceRelPos),
|
2019-10-11 05:02:53 -04:00
|
|
|
x, z,
|
2020-11-06 11:54:01 -05:00
|
|
|
ItemTypeToString(BlockType[CheckType]),
|
|
|
|
ItemTypeToString(SoilType),
|
|
|
|
Meta
|
2019-10-11 05:02:53 -04:00
|
|
|
);
|
2020-11-06 11:54:01 -05:00
|
|
|
|
|
|
|
// Place a randomly-facing produce:
|
|
|
|
a_Chunk.SetBlock(ProduceRelPos, ProduceBlockType, Meta);
|
2019-10-11 05:02:53 -04:00
|
|
|
}
|
|
|
|
}
|
2015-06-30 10:50:15 -04:00
|
|
|
}
|
2020-11-06 11:54:01 -05:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
// https://minecraft.gamepedia.com/Pumpkin_Seeds#Breaking
|
|
|
|
// https://minecraft.gamepedia.com/Melon_Seeds#Breaking
|
|
|
|
/** The array describes how many seed may be dropped at which age. The inner arrays describe the probability to drop 0, 1, 2, 3 seeds.
|
|
|
|
The outer describes the age of the stem. */
|
|
|
|
static constexpr std::array<std::array<double, 4>, 8> m_AgeSeedDropProbability
|
|
|
|
{
|
|
|
|
{
|
|
|
|
{
|
|
|
|
81.3, 17.42, 1.24, 0.03
|
|
|
|
},
|
|
|
|
{
|
|
|
|
65.1, 30.04, 4.62, 0.24
|
|
|
|
},
|
|
|
|
{
|
|
|
|
51.2, 38.4, 9.6, 0.8
|
|
|
|
},
|
|
|
|
{
|
|
|
|
39.44, 43.02, 15.64, 1.9
|
|
|
|
},
|
|
|
|
{
|
|
|
|
29.13, 44.44, 22.22, 3.7
|
|
|
|
},
|
|
|
|
{
|
|
|
|
21.6, 43.2, 28.8, 6.4
|
|
|
|
},
|
|
|
|
{
|
|
|
|
15.17, 39.82, 34.84, 10.16
|
|
|
|
},
|
|
|
|
{
|
|
|
|
10.16, 34.84, 39.82, 15.17
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2013-07-29 07:13:03 -04:00
|
|
|
} ;
|
|
|
|
|
2019-10-11 05:02:53 -04:00
|
|
|
using cBlockMelonStemHandler = cBlockStemsHandler<E_BLOCK_MELON, E_ITEM_MELON_SEEDS>;
|
|
|
|
using cBlockPumpkinStemHandler = cBlockStemsHandler<E_BLOCK_PUMPKIN, E_ITEM_PUMPKIN_SEEDS>;
|