FastRandom rewrite (#3754)
This commit is contained in:
parent
9b0eb118b3
commit
360d8eade0
@ -174,7 +174,7 @@ void cDropSpenserEntity::DropFromSlot(cChunk & a_Chunk, int a_SlotNum)
|
||||
cItems Pickups;
|
||||
Pickups.push_back(m_Contents.RemoveOneItem(a_SlotNum));
|
||||
|
||||
const int PickupSpeed = m_World->GetTickRandomNumber(4) + 2; // At least 2, at most 6
|
||||
const int PickupSpeed = GetRandomProvider().RandInt(2, 6); // At least 2, at most 6
|
||||
int PickupSpeedX = 0, PickupSpeedY = 0, PickupSpeedZ = 0;
|
||||
switch (Meta & E_META_DROPSPENSER_FACING_MASK)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
|
||||
void cMobSpawnerEntity::ResetTimer(void)
|
||||
{
|
||||
m_SpawnDelay = static_cast<short>(200 + m_World->GetTickRandomNumber(600));
|
||||
m_SpawnDelay = GetRandomProvider().RandInt<short>(200, 800);
|
||||
m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
|
||||
|
||||
virtual bool Item(cChunk * a_Chunk)
|
||||
{
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
bool EntitiesSpawned = false;
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
@ -148,9 +148,9 @@ void cMobSpawnerEntity::SpawnEntity(void)
|
||||
break;
|
||||
}
|
||||
|
||||
int RelX = static_cast<int>(m_RelX + static_cast<double>(Random.NextFloat() - Random.NextFloat()) * 4.0);
|
||||
int RelY = m_RelY + Random.NextInt(3) - 1;
|
||||
int RelZ = static_cast<int>(m_RelZ + static_cast<double>(Random.NextFloat() - Random.NextFloat()) * 4.0);
|
||||
int RelX = m_RelX + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0);
|
||||
int RelY = m_RelY + Random.RandInt(-1, 1);
|
||||
int RelZ = m_RelZ + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0);
|
||||
|
||||
cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ);
|
||||
if ((Chunk == nullptr) || !Chunk->IsValid())
|
||||
@ -171,7 +171,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
|
||||
}
|
||||
|
||||
Monster->SetPosition(PosX, RelY, PosZ);
|
||||
Monster->SetYaw(Random.NextFloat() * 360.0f);
|
||||
Monster->SetYaw(Random.RandReal(360.0f));
|
||||
if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID)
|
||||
{
|
||||
EntitiesSpawned = true;
|
||||
|
@ -67,8 +67,7 @@ public:
|
||||
)
|
||||
)
|
||||
{
|
||||
MTRand r1;
|
||||
if (r1.randInt(10) == 5)
|
||||
if (GetRandomProvider().RandBool(0.10))
|
||||
{
|
||||
cItems Pickups;
|
||||
if (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS)
|
||||
|
@ -30,9 +30,7 @@ public:
|
||||
|
||||
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
|
||||
if (Random.NextInt(5) == 0)
|
||||
if (GetRandomProvider().RandBool(0.20))
|
||||
{
|
||||
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
|
||||
NIBBLETYPE TypeMeta = Meta & 0x03;
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
|
||||
{
|
||||
cFastRandom rand;
|
||||
auto & rand = GetRandomProvider();
|
||||
|
||||
// If not fully grown, drop the "seed" of whatever is growing:
|
||||
if (a_Meta < RipeMeta)
|
||||
@ -51,30 +51,30 @@ public:
|
||||
{
|
||||
case E_BLOCK_BEETROOTS:
|
||||
{
|
||||
char SeedCount = static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.push_back(cItem(E_ITEM_BEETROOT_SEEDS, SeedCount, 0));
|
||||
char BeetrootCount = static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.push_back(cItem(E_ITEM_BEETROOT, BeetrootCount, 0));
|
||||
char SeedCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.emplace_back(E_ITEM_BEETROOT_SEEDS, SeedCount, 0);
|
||||
char BeetrootCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.emplace_back(E_ITEM_BEETROOT, BeetrootCount, 0);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_CROPS:
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_WHEAT, 1, 0));
|
||||
a_Pickups.push_back(cItem(E_ITEM_SEEDS, static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.emplace_back(E_ITEM_WHEAT, 1, 0);
|
||||
a_Pickups.emplace_back(E_ITEM_SEEDS, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_CARROTS:
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_CARROT, static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
|
||||
a_Pickups.emplace_back(E_ITEM_CARROT, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_POTATOES:
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_POTATO, static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2
|
||||
if (rand.NextInt(21) == 0)
|
||||
a_Pickups.emplace_back(E_ITEM_POTATO, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
|
||||
if (rand.RandBool(0.05))
|
||||
{
|
||||
// With a 5% chance, drop a poisonous potato as well
|
||||
a_Pickups.push_back(cItem(E_ITEM_POISONOUS_POTATO, 1, 0));
|
||||
a_Pickups.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -46,11 +46,10 @@ public:
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
// Drop 0-3 sticks
|
||||
cFastRandom random;
|
||||
int chance = random.NextInt(3);
|
||||
char chance = GetRandomProvider().RandInt<char>(3);
|
||||
if (chance != 0)
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_STICK, static_cast<char>(chance), 0));
|
||||
a_Pickups.emplace_back(E_ITEM_STICK, chance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +73,7 @@ public:
|
||||
// Spawn the pickups:
|
||||
if (!Drops.empty())
|
||||
{
|
||||
MTRand r1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
|
||||
// Mid-block position first
|
||||
double MicroX, MicroY, MicroZ;
|
||||
@ -83,8 +82,8 @@ public:
|
||||
MicroZ = a_BlockZ + 0.5;
|
||||
|
||||
// Add random offset second
|
||||
MicroX += r1.rand(1) - 0.5;
|
||||
MicroZ += r1.rand(1) - 0.5;
|
||||
MicroX += r1.RandReal<double>(-0.5, 0.5);
|
||||
MicroZ += r1.RandReal<double>(-0.5, 0.5);
|
||||
|
||||
a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ);
|
||||
}
|
||||
|
@ -70,12 +70,12 @@ public:
|
||||
}
|
||||
|
||||
// Grass spreads to adjacent dirt blocks:
|
||||
cFastRandom rand;
|
||||
auto & rand = GetRandomProvider();
|
||||
for (int i = 0; i < 2; i++) // Pick two blocks to grow to
|
||||
{
|
||||
int OfsX = rand.NextInt(3) - 1; // [-1 .. 1]
|
||||
int OfsY = rand.NextInt(5) - 3; // [-3 .. 1]
|
||||
int OfsZ = rand.NextInt(3) - 1; // [-1 .. 1]
|
||||
int OfsX = rand.RandInt(-1, 1);
|
||||
int OfsY = rand.RandInt(-3, 1);
|
||||
int OfsZ = rand.RandInt(-1, 1);
|
||||
|
||||
BLOCKTYPE DestBlock;
|
||||
NIBBLETYPE DestMeta;
|
||||
|
@ -18,10 +18,8 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
|
||||
// Add more than one dust
|
||||
a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, static_cast<char>(2 + Random.NextInt(3)), 0));
|
||||
a_Pickups.emplace_back(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt<char>(2, 4), 0);
|
||||
}
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
|
@ -18,8 +18,7 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
if (Random.NextInt(10) == 0)
|
||||
if (GetRandomProvider().RandBool(0.10))
|
||||
{
|
||||
a_Pickups.Add(E_ITEM_FLINT, 1, 0);
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
|
||||
if (!Pickups.empty())
|
||||
{
|
||||
MTRand r1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
|
||||
// Mid-block position first
|
||||
double MicroX, MicroY, MicroZ;
|
||||
@ -535,8 +535,8 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
MicroZ = a_BlockZ + 0.5;
|
||||
|
||||
// Add random offset second
|
||||
MicroX += r1.rand(1) - 0.5;
|
||||
MicroZ += r1.rand(1) - 0.5;
|
||||
MicroX += r1.RandReal<double>(-0.5, 0.5);
|
||||
MicroZ += r1.RandReal<double>(-0.5, 0.5);
|
||||
|
||||
a_WorldInterface.SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
|
||||
}
|
||||
|
@ -37,22 +37,22 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
cFastRandom rand;
|
||||
auto & rand = GetRandomProvider();
|
||||
|
||||
// There is a chance to drop a sapling that varies depending on the type of leaf broken.
|
||||
// TODO: Take into account fortune for sapling drops.
|
||||
int chance;
|
||||
double chance = 0.0;
|
||||
if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_JUNGLE))
|
||||
{
|
||||
// Jungle leaves have a 2.5% chance of dropping a sapling.
|
||||
chance = rand.NextInt(40);
|
||||
chance = 0.025;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other leaves have a 5% chance of dropping a sapling.
|
||||
chance = rand.NextInt(20);
|
||||
chance = 0.05;
|
||||
}
|
||||
if (chance == 0)
|
||||
if (rand.RandBool(chance))
|
||||
{
|
||||
a_Pickups.push_back(
|
||||
cItem(
|
||||
@ -66,7 +66,7 @@ public:
|
||||
// 0.5 % chance of dropping an apple, if the leaves' type is Apple Leaves
|
||||
if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_APPLE))
|
||||
{
|
||||
if (rand.NextInt(200) == 0)
|
||||
if (rand.RandBool(0.005))
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
a_Pickups.push_back(cItem(E_ITEM_MELON_SLICE, static_cast<char>(3 + Random.NextInt(5)), 0));
|
||||
a_Pickups.emplace_back(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt<char>(3, 7), 0);
|
||||
}
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
|
||||
cItems Pickups;
|
||||
Pickups.Add(E_ITEM_HEAD, 1, static_cast<short>(MobHeadEntity->GetType()));
|
||||
MTRand r1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
|
||||
// Mid-block position first
|
||||
double MicroX, MicroY, MicroZ;
|
||||
@ -51,8 +51,8 @@ public:
|
||||
MicroZ = MobHeadEntity->GetPosZ() + 0.5;
|
||||
|
||||
// Add random offset second
|
||||
MicroX += r1.rand(1) - 0.5;
|
||||
MicroZ += r1.rand(1) - 0.5;
|
||||
MicroX += r1.RandReal<double>(-0.5, 0.5);
|
||||
MicroZ += r1.RandReal<double>(-0.5, 0.5);
|
||||
|
||||
MobHeadEntity->GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
|
||||
return false;
|
||||
|
@ -45,8 +45,8 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
int Reward = 15 + Random.NextInt(15) + Random.NextInt(15);
|
||||
auto & Random = GetRandomProvider();
|
||||
int Reward = 15 + Random.RandInt(14) + Random.RandInt(14);
|
||||
a_WorldInterface.SpawnExperienceOrb(static_cast<double>(a_BlockX), static_cast<double>(a_BlockY + 1), static_cast<double>(a_BlockZ), Reward);
|
||||
}
|
||||
} ;
|
||||
|
@ -21,12 +21,12 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
|
||||
{
|
||||
cFastRandom rand;
|
||||
auto & rand = GetRandomProvider();
|
||||
|
||||
if (a_Meta == 0x3)
|
||||
{
|
||||
// Fully grown, drop the entire produce:
|
||||
a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, static_cast<char>(1 + (rand.NextInt(3) + rand.NextInt(3))) / 2, 0));
|
||||
a_Pickups.emplace_back(E_ITEM_NETHER_WART, 1 + (rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -20,19 +20,19 @@ public:
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
switch (m_BlockType)
|
||||
{
|
||||
case E_BLOCK_LAPIS_ORE:
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_DYE, static_cast<char>(4 + Random.NextInt(5)), 4));
|
||||
a_Pickups.emplace_back(E_ITEM_DYE, Random.RandInt<char>(4, 8), 4);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_REDSTONE_ORE:
|
||||
case E_BLOCK_REDSTONE_ORE_GLOWING:
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, static_cast<char>(4 + Random.NextInt(2)), 0));
|
||||
a_Pickups.emplace_back(E_ITEM_REDSTONE_DUST, Random.RandInt<char>(4, 5), 0);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_DIAMOND_ORE:
|
||||
@ -84,7 +84,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
int Reward = 0;
|
||||
|
||||
switch (m_BlockType)
|
||||
@ -93,27 +93,27 @@ public:
|
||||
case E_BLOCK_LAPIS_ORE:
|
||||
{
|
||||
// Lapis and nether quartz get 2 - 5 experience
|
||||
Reward = Random.NextInt(4) + 2;
|
||||
Reward = Random.RandInt(2, 5);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_REDSTONE_ORE:
|
||||
case E_BLOCK_REDSTONE_ORE_GLOWING:
|
||||
{
|
||||
// Redstone gets 1 - 5 experience
|
||||
Reward = Random.NextInt(5) + 1;
|
||||
Reward = Random.RandInt(1, 5);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_DIAMOND_ORE:
|
||||
case E_BLOCK_EMERALD_ORE:
|
||||
{
|
||||
// Diamond and emerald get 3 - 7 experience
|
||||
Reward = Random.NextInt(5) + 3;
|
||||
Reward = Random.RandInt(3, 7);
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_COAL_ORE:
|
||||
{
|
||||
// Coal gets 0 - 2 experience
|
||||
Reward = Random.NextInt(3);
|
||||
Reward = Random.RandInt(2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -75,10 +75,9 @@ protected:
|
||||
*/
|
||||
virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||
{
|
||||
cFastRandom rand;
|
||||
// Plant can grow if it has the required amount of light, and it passes a random chance based on surrounding blocks
|
||||
PlantAction Action = HasEnoughLight(a_Chunk, a_RelX, a_RelY, a_RelZ);
|
||||
if ((Action == paGrowth) && (rand.NextInt(GetGrowthChance(a_Chunk, a_RelX, a_RelY, a_RelZ)) != 0))
|
||||
if ((Action == paGrowth) && !GetRandomProvider().RandBool(1.0 / GetGrowthChance(a_Chunk, a_RelX, a_RelY, a_RelZ)))
|
||||
{
|
||||
Action = paStay;
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ public:
|
||||
|
||||
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
|
||||
{
|
||||
cFastRandom Random;
|
||||
if (Random.NextInt(2000) != 0)
|
||||
if (GetRandomProvider().RandBool(0.9995))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -37,16 +37,16 @@ public:
|
||||
// Only grow if we have the right amount of light
|
||||
if (Light > 8)
|
||||
{
|
||||
cFastRandom random;
|
||||
auto & random = GetRandomProvider();
|
||||
// Only grow if we are in the right growth stage and have the right amount of space around them.
|
||||
if (((Meta & 0x08) != 0) && (random.NextInt(99) < 45) && CanGrowAt(a_Chunk, a_RelX, a_RelY, a_RelZ, Meta))
|
||||
if (((Meta & 0x08) != 0) && random.RandBool(0.45) && CanGrowAt(a_Chunk, a_RelX, a_RelY, a_RelZ, Meta))
|
||||
{
|
||||
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
a_Chunk.GetWorld()->GrowTree(BlockX, a_RelY, BlockZ);
|
||||
}
|
||||
// Only move to the next growth stage if we haven't gone there yet
|
||||
else if (((Meta & 0x08) == 0) && (random.NextInt(99) < 45))
|
||||
else if (((Meta & 0x08) == 0) && random.RandBool(0.45))
|
||||
{
|
||||
a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta | 0x08);
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ public:
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
// Reset meta to 0
|
||||
cFastRandom Random;
|
||||
a_Pickups.push_back(cItem(E_ITEM_PRISMARINE_CRYSTALS, static_cast<char>(2 + Random.NextInt(2)), 0));
|
||||
a_Pickups.emplace_back(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt<char>(2, 3), 0);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
@ -26,8 +26,7 @@ public:
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
// Drop seeds, sometimes
|
||||
cFastRandom Random;
|
||||
if (Random.NextInt(8) == 0)
|
||||
if (GetRandomProvider().RandBool(0.125))
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0));
|
||||
}
|
||||
@ -47,7 +46,7 @@ public:
|
||||
// Spawn the pickups:
|
||||
if (!Drops.empty())
|
||||
{
|
||||
MTRand r1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
|
||||
// Mid-block position first
|
||||
double MicroX, MicroY, MicroZ;
|
||||
@ -56,8 +55,8 @@ public:
|
||||
MicroZ = a_BlockZ + 0.5;
|
||||
|
||||
// Add random offset second
|
||||
MicroX += r1.rand(1) - 0.5;
|
||||
MicroZ += r1.rand(1) - 0.5;
|
||||
MicroX += r1.RandReal<double>(-0.5, 0.5);
|
||||
MicroZ += r1.RandReal<double>(-0.5, 0.5);
|
||||
|
||||
a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ);
|
||||
}
|
||||
|
@ -507,14 +507,19 @@ void cChunk::CollectMobCensus(cMobCensus & toFill)
|
||||
|
||||
void cChunk::GetThreeRandomNumbers(int & a_X, int & a_Y, int & a_Z, int a_MaxX, int a_MaxY, int a_MaxZ)
|
||||
{
|
||||
ASSERT(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff);
|
||||
int Random = m_World->GetTickRandomNumber(0x00ffffff);
|
||||
a_X = Random % (a_MaxX * 2);
|
||||
a_Y = (Random / (a_MaxX * 2)) % (a_MaxY * 2);
|
||||
a_Z = ((Random / (a_MaxX * 2)) / (a_MaxY * 2)) % (a_MaxZ * 2);
|
||||
a_X /= 2;
|
||||
a_Y /= 2;
|
||||
a_Z /= 2;
|
||||
ASSERT(
|
||||
(a_MaxX > 0) && (a_MaxY > 0) && (a_MaxZ > 0) &&
|
||||
(a_MaxX <= std::numeric_limits<int>::max() / a_MaxY) && // a_MaxX * a_MaxY doesn't overflow
|
||||
(a_MaxX * a_MaxY <= std::numeric_limits<int>::max() / a_MaxZ) // a_MaxX * a_MaxY * a_MaxZ doesn't overflow
|
||||
);
|
||||
|
||||
// MTRand gives an inclusive range [0, Max] but this gives the exclusive range [0, Max)
|
||||
int OverallMax = (a_MaxX - 1) * (a_MaxY - 1) * (a_MaxZ - 1);
|
||||
int Random = m_World->GetTickRandomNumber(OverallMax);
|
||||
|
||||
a_X = Random % a_MaxX;
|
||||
a_Y = (Random / a_MaxX) % a_MaxY;
|
||||
a_Z = ((Random / a_MaxX) / a_MaxY) % a_MaxZ;
|
||||
}
|
||||
|
||||
|
||||
@ -848,7 +853,7 @@ void cChunk::TickBlocks(void)
|
||||
void cChunk::ApplyWeatherToTop()
|
||||
{
|
||||
if (
|
||||
(m_World->GetTickRandomNumber(100) != 0) ||
|
||||
(GetRandomProvider().RandBool(0.99)) ||
|
||||
(
|
||||
(m_World->GetWeather() != eWeather_Rain) &&
|
||||
(m_World->GetWeather() != eWeather_ThunderStorm)
|
||||
@ -932,8 +937,10 @@ void cChunk::ApplyWeatherToTop()
|
||||
|
||||
|
||||
|
||||
bool 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)
|
||||
{
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
// Convert the stem BlockType into produce BlockType
|
||||
BLOCKTYPE ProduceType;
|
||||
switch (a_BlockType)
|
||||
@ -969,7 +976,7 @@ bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
|
||||
|
||||
// Pick a direction in which to place the produce:
|
||||
int x = 0, z = 0;
|
||||
int CheckType = a_TickRandom.randInt(3); // The index to the neighbors array which should be checked for emptiness
|
||||
int CheckType = Random.RandInt(3); // The index to the neighbors array which should be checked for emptiness
|
||||
switch (CheckType)
|
||||
{
|
||||
case 0: x = 1; break;
|
||||
@ -1001,7 +1008,7 @@ bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
|
||||
case E_BLOCK_FARMLAND:
|
||||
{
|
||||
// Place a randomly-facing produce:
|
||||
NIBBLETYPE Meta = (ProduceType == E_BLOCK_MELON) ? 0 : static_cast<NIBBLETYPE>(a_TickRandom.randInt(4) % 4);
|
||||
NIBBLETYPE Meta = (ProduceType == E_BLOCK_MELON) ? 0 : static_cast<NIBBLETYPE>(Random.RandInt(4) % 4);
|
||||
LOGD("Growing melon / pumpkin at {%d, %d, %d} (<%d, %d> from stem), overwriting %s, growing on top of %s, meta %d",
|
||||
a_RelX + x + m_PosX * cChunkDef::Width, a_RelY, a_RelZ + z + m_PosZ * cChunkDef::Width,
|
||||
x, z,
|
||||
|
@ -27,7 +27,6 @@ namespace Json
|
||||
class cWorld;
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class MTRand;
|
||||
class cPlayer;
|
||||
class cChunkMap;
|
||||
class cBeaconEntity;
|
||||
@ -609,7 +608,7 @@ private:
|
||||
bool GrowTallGrass (int a_RelX, int a_RelY, int a_RelZ);
|
||||
|
||||
/** 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);
|
||||
bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType);
|
||||
|
||||
/** 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);
|
||||
|
@ -1735,7 +1735,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
case E_BLOCK_TNT:
|
||||
{
|
||||
// Activate the TNT, with a random fuse between 10 to 30 game ticks
|
||||
int FuseTime = 10 + m_World->GetTickRandomNumber(20);
|
||||
int FuseTime = GetRandomProvider().RandInt(10, 30);
|
||||
m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime);
|
||||
area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0);
|
||||
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
|
||||
@ -1775,7 +1775,8 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
|
||||
default:
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
|
||||
auto & Random = GetRandomProvider();
|
||||
if (Random.RandBool(0.25)) // 25% chance of pickups
|
||||
{
|
||||
cItems Drops;
|
||||
cBlockHandler * Handler = BlockHandler(Block);
|
||||
@ -1783,7 +1784,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc.
|
||||
m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z);
|
||||
}
|
||||
else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around
|
||||
else if ((m_World->GetTNTShrapnelLevel() > slNone) && Random.RandBool(0.20)) // 20% chance of flinging stuff around
|
||||
{
|
||||
// If the block is shrapnel-able, make a falling block entity out of it:
|
||||
if (
|
||||
@ -2516,7 +2517,7 @@ void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty)
|
||||
|
||||
|
||||
|
||||
bool 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)
|
||||
{
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ);
|
||||
@ -2525,7 +2526,7 @@ bool cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK
|
||||
cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ);
|
||||
if (Chunk != nullptr)
|
||||
{
|
||||
return Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_Rand);
|
||||
return Chunk->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
class cWorld;
|
||||
class cWorldInterface;
|
||||
class cItem;
|
||||
class MTRand;
|
||||
class cChunkStay;
|
||||
class cChunk;
|
||||
class cPlayer;
|
||||
@ -362,7 +361,7 @@ public:
|
||||
void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty);
|
||||
|
||||
/** 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);
|
||||
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; 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);
|
||||
|
@ -1012,14 +1012,12 @@ void cEnchantments::CheckEnchantmentConflictsFromVector(cWeightedEnchantments &
|
||||
|
||||
cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments)
|
||||
{
|
||||
cFastRandom Random;
|
||||
|
||||
int AllWeights = 0;
|
||||
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
|
||||
{
|
||||
AllWeights += (*it).m_Weight;
|
||||
}
|
||||
int RandomNumber = Random.GenerateRandomInteger(0, AllWeights - 1);
|
||||
int RandomNumber = GetRandomProvider().RandInt(AllWeights - 1);
|
||||
for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it)
|
||||
{
|
||||
RandomNumber -= (*it).m_Weight;
|
||||
|
@ -495,12 +495,11 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
int Chance = static_cast<int>(ThornsLevel * 15);
|
||||
|
||||
cFastRandom Random;
|
||||
int RandomValue = Random.GenerateRandomInteger(0, 100);
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
if (RandomValue <= Chance)
|
||||
if (Random.RandBool(Chance / 100.0))
|
||||
{
|
||||
a_TDI.Attacker->TakeDamage(dtAttack, this, 0, Random.GenerateRandomInteger(1, 4), 0);
|
||||
a_TDI.Attacker->TakeDamage(dtAttack, this, 0, Random.RandInt(1, 4), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,8 +573,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
TotalEPF = 25;
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
float RandomValue = Random.GenerateRandomInteger(50, 100) * 0.01f;
|
||||
float RandomValue = GetRandomProvider().RandReal(0.5f, 1.0f);
|
||||
|
||||
TotalEPF = ceil(TotalEPF * RandomValue);
|
||||
|
||||
|
@ -40,6 +40,6 @@ void cExpBottleEntity::Break(const Vector3d &a_HitPos)
|
||||
{
|
||||
// Spawn an experience orb with a reward between 3 and 11.
|
||||
m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SPLASH_POTION, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
|
||||
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
||||
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), GetRandomProvider().RandInt(3, 11));
|
||||
Destroy();
|
||||
}
|
||||
|
@ -128,6 +128,8 @@ void cFloater::SpawnOn(cClientHandle & a_Client)
|
||||
|
||||
void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
HandlePhysics(a_Dt, a_Chunk);
|
||||
if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT))
|
||||
&& (m_World->GetBlockMeta(POSX_TOINT, POSY_TOINT, POSX_TOINT) == 0))
|
||||
@ -141,13 +143,13 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
SetPosY(GetPosY() - 1);
|
||||
m_CanPickupItem = true;
|
||||
m_PickupCountDown = 20;
|
||||
m_CountDownTime = 100 + m_World->GetTickRandomNumber(800);
|
||||
m_CountDownTime = Random.RandInt(100, 900);
|
||||
LOGD("Floater %i can be picked up", GetUniqueID());
|
||||
}
|
||||
else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
|
||||
{
|
||||
LOGD("Started producing particles for floater %i", GetUniqueID());
|
||||
m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
|
||||
m_ParticlePos.Set(GetPosX() + Random.RandInt(-4, 4), GetPosY(), GetPosZ() + Random.RandInt(-4, 4));
|
||||
m_World->GetBroadcaster().BroadcastParticleEffect("splash", static_cast<Vector3f>(m_ParticlePos), Vector3f{}, 0, 15);
|
||||
}
|
||||
else if (m_CountDownTime < 20)
|
||||
@ -159,14 +161,14 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
m_CountDownTime--;
|
||||
if (m_World->GetHeight(POSX_TOINT, POSZ_TOINT) == POSY_TOINT)
|
||||
{
|
||||
if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
|
||||
if (m_World->IsWeatherWet() && Random.RandBool(0.25)) // 25% chance of an extra countdown when being rained on.
|
||||
{
|
||||
m_CountDownTime--;
|
||||
}
|
||||
}
|
||||
else // if the floater is underground it has a 50% chance of not decreasing the countdown.
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(1) == 0)
|
||||
if (Random.RandBool())
|
||||
{
|
||||
m_CountDownTime++;
|
||||
}
|
||||
|
@ -1069,9 +1069,9 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
case dtRangedAttack: DamageText = "was shot"; break;
|
||||
case dtLightning: DamageText = "was plasmified by lightining"; break;
|
||||
case dtFalling: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "fell to death" : "hit the ground too hard"; break;
|
||||
case dtFalling: DamageText = GetRandomProvider().RandBool() ? "fell to death" : "hit the ground too hard"; break;
|
||||
case dtDrowning: DamageText = "drowned"; break;
|
||||
case dtSuffocating: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "git merge'd into a block" : "fused with a block"; break;
|
||||
case dtSuffocating: DamageText = GetRandomProvider().RandBool() ? "git merge'd into a block" : "fused with a block"; break;
|
||||
case dtStarving: DamageText = "forgot the importance of food"; break;
|
||||
case dtCactusContact: DamageText = "was impaled on a cactus"; break;
|
||||
case dtLavaContact: DamageText = "was melted by lava"; break;
|
||||
@ -2295,18 +2295,17 @@ void cPlayer::UseEquippedItem(int a_Amount)
|
||||
int UnbreakingLevel = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking));
|
||||
if (UnbreakingLevel > 0)
|
||||
{
|
||||
int chance;
|
||||
double chance = 0.0;
|
||||
if (ItemCategory::IsArmor(Item.m_ItemType))
|
||||
{
|
||||
chance = 60 + (40 / (UnbreakingLevel + 1));
|
||||
chance = 0.6 + (0.4 / (UnbreakingLevel + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 100 / (UnbreakingLevel + 1);
|
||||
chance = 1.0 / (UnbreakingLevel + 1);
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
if (Random.NextInt(101) <= chance)
|
||||
if (GetRandomProvider().RandBool(chance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -74,11 +74,12 @@ void cThrownEggEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
|
||||
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(7) == 1)
|
||||
auto & Random = GetRandomProvider();
|
||||
if (Random.RandBool(0.125))
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, true);
|
||||
}
|
||||
else if (m_World->GetTickRandomNumber(32) == 1)
|
||||
else if (Random.RandBool(1.0 / 33.0))
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, true);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, mtChicken, true);
|
||||
|
@ -1,11 +1,11 @@
|
||||
|
||||
// FastRandom.cpp
|
||||
|
||||
// Implements the cFastRandom class representing a fast random number generator
|
||||
|
||||
#include "Globals.h"
|
||||
#include "FastRandom.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
|
||||
#if defined (__GNUC__)
|
||||
@ -13,109 +13,50 @@
|
||||
#elif defined (_MSC_VER)
|
||||
#define ATTRIBUTE_TLS static __declspec(thread)
|
||||
#else
|
||||
#error "Unknown thread local storage qualifier"
|
||||
#define ATTRIBUTE_TLS thread_local
|
||||
#endif
|
||||
|
||||
static unsigned int GetRandomSeed()
|
||||
|
||||
|
||||
|
||||
|
||||
MTRand & GetRandomProvider()
|
||||
{
|
||||
ATTRIBUTE_TLS bool SeedCounterInitialized = 0;
|
||||
ATTRIBUTE_TLS unsigned int SeedCounter = 0;
|
||||
// Some compilers don't support thread_local for non-POD types, this is purely a work around for that restriction.
|
||||
// There should be minimal overhead for the non-initializing case and all thread's instances are deleted properly.
|
||||
ATTRIBUTE_TLS MTRand * LocalPtr = nullptr;
|
||||
if (LocalPtr == nullptr)
|
||||
{
|
||||
// This list allows deletion of elements as if they had static storage duration
|
||||
static std::mutex CSDeleteList;
|
||||
static std::list<std::unique_ptr<MTRand>> DeleteList;
|
||||
|
||||
cRandomDeviceSeeder seeder;
|
||||
auto NewInstance = cpp14::make_unique<MTRand>(seeder);
|
||||
auto TempPtr = NewInstance.get();
|
||||
|
||||
std::lock_guard<std::mutex> Lock(CSDeleteList);
|
||||
DeleteList.push_front(std::move(NewInstance));
|
||||
LocalPtr = TempPtr; // Set after push_back so LocalPtr won't dangle if it throws
|
||||
}
|
||||
return *LocalPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UInt32 Detail::GetRandomSeed()
|
||||
{
|
||||
ATTRIBUTE_TLS bool SeedCounterInitialized = false;
|
||||
ATTRIBUTE_TLS UInt32 SeedCounter = 0;
|
||||
|
||||
if (!SeedCounterInitialized)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<unsigned int> dist;
|
||||
std::uniform_int_distribution<UInt32> dist;
|
||||
SeedCounter = dist(rd);
|
||||
SeedCounterInitialized = true;
|
||||
}
|
||||
return ++SeedCounter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cFastRandom:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cFastRandom::cFastRandom(void) :
|
||||
m_LinearRand(GetRandomSeed())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cFastRandom::NextInt(int a_Range)
|
||||
{
|
||||
std::uniform_int_distribution<> distribution(0, a_Range - 1);
|
||||
return distribution(m_LinearRand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float cFastRandom::NextFloat(float a_Range)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0, a_Range);
|
||||
return distribution(m_LinearRand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
|
||||
{
|
||||
std::uniform_int_distribution<> distribution(a_Begin, a_End);
|
||||
return distribution(m_LinearRand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MTRand:
|
||||
|
||||
MTRand::MTRand() :
|
||||
m_MersenneRand(GetRandomSeed())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int MTRand::randInt(int a_Range)
|
||||
{
|
||||
std::uniform_int_distribution<> distribution(0, a_Range);
|
||||
return distribution(m_MersenneRand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int MTRand::randInt()
|
||||
{
|
||||
std::uniform_int_distribution<> distribution(0, std::numeric_limits<int>::max());
|
||||
return distribution(m_MersenneRand);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
double MTRand::rand(double a_Range)
|
||||
{
|
||||
std::uniform_real_distribution<> distribution(0, a_Range);
|
||||
return distribution(m_MersenneRand);
|
||||
}
|
||||
|
206
src/FastRandom.h
206
src/FastRandom.h
@ -4,17 +4,10 @@
|
||||
// Declares the cFastRandom class representing a fast random number generator
|
||||
|
||||
/*
|
||||
The cFastRandom aims to provide a very fast, although not very cryptographically secure, random generator.
|
||||
It is fast to instantiate, fast to query next, and partially multi-thread-safe.
|
||||
It is multi-thread-safe in the sense that it can be accessed from multiple threads without crashing, but it may
|
||||
yield duplicate numbers in that case.
|
||||
|
||||
Internally, this works similar to cNoise's integral noise generation, with some predefined inputs: the seed is
|
||||
taken from a global counter and the random is calculated using a counter that is incremented on each use (hence
|
||||
the multi-thread duplication). Two alternatives exists for each function, one that takes a range parameter,
|
||||
and another that takes an additional "salt" parameter; this salt is used as an additional input to the random,
|
||||
in order to avoid multi-thread duplication. If two threads both use the class at the same time with different
|
||||
salts, the values they get will be different.
|
||||
The cFastRandom alias should be avoided in favor of the result of a call to GetRandomProvider().
|
||||
The MTRand generator used is faster, has a better range and provides higher quality randomness.
|
||||
Note that MTRand is relatively costly to construct and so instances should be long lived,
|
||||
prefer calls to GetRandomProvider over creating new instances.
|
||||
*/
|
||||
|
||||
|
||||
@ -23,58 +16,195 @@ salts, the values they get will be different.
|
||||
|
||||
#pragma once
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cFastRandom
|
||||
namespace Detail
|
||||
{
|
||||
/** Returns a low quality seed. */
|
||||
UInt32 GetRandomSeed();
|
||||
|
||||
/** Aliases true_type if Char is any variant of char ignoring signed-ness. */
|
||||
template <class Char>
|
||||
using IsChar = typename std::is_same<typename std::make_signed<Char>::type, signed char>::type;
|
||||
|
||||
template <class IntType>
|
||||
struct cUniformImpl :
|
||||
public std::conditional<
|
||||
IsChar<IntType>::value,
|
||||
typename std::conditional< // Match signed-ness of IntType
|
||||
std::is_signed<IntType>::value,
|
||||
std::uniform_int_distribution<short>,
|
||||
std::uniform_int_distribution<unsigned short>
|
||||
>::type,
|
||||
std::uniform_int_distribution<IntType>
|
||||
>
|
||||
{
|
||||
};
|
||||
|
||||
/** uniform_int_distribution<char> is undefined so this aliases a valid type. */
|
||||
template <class IntType>
|
||||
using cUniform = typename cUniformImpl<IntType>::type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Class to wrap any random engine to provide a more convenient interface. */
|
||||
template <class RandomEngine>
|
||||
class cRandomWrapper
|
||||
{
|
||||
public:
|
||||
/** Initialize with a low quality seed. */
|
||||
cRandomWrapper():
|
||||
m_Engine(Detail::GetRandomSeed())
|
||||
{
|
||||
}
|
||||
|
||||
cFastRandom(void);
|
||||
|
||||
/** Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M */
|
||||
int NextInt(int a_Range);
|
||||
/** Initialize with a SeedSequence. */
|
||||
template <class SeedSeq>
|
||||
cRandomWrapper(SeedSeq & a_SeedSeq):
|
||||
m_Engine(a_SeedSeq)
|
||||
{
|
||||
}
|
||||
|
||||
/** Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M */
|
||||
float NextFloat(float a_Range);
|
||||
|
||||
/** Returns a random float between 0 and 1. */
|
||||
float NextFloat(void) { return NextFloat(1); }
|
||||
|
||||
/** Returns a random int in the range [a_Begin .. a_End] */
|
||||
int GenerateRandomInteger(int a_Begin, int a_End);
|
||||
/** Return a random IntType in the range [a_Min, a_Max]. */
|
||||
template <class IntType = int, class ArgType>
|
||||
IntType RandInt(ArgType a_Min, ArgType a_Max)
|
||||
{
|
||||
ASSERT(
|
||||
(a_Max >= a_Min) &&
|
||||
(a_Max <= std::numeric_limits<IntType>::max()) &&
|
||||
(a_Min >= std::numeric_limits<IntType>::min())
|
||||
);
|
||||
Detail::cUniform<IntType> dist(
|
||||
static_cast<IntType>(a_Min),
|
||||
static_cast<IntType>(a_Max)
|
||||
);
|
||||
return static_cast<IntType>(dist(m_Engine));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random IntType in the range [0, a_Max]. */
|
||||
template <class IntType = int, class ArgType>
|
||||
IntType RandInt(ArgType a_Max)
|
||||
{
|
||||
ASSERT((a_Max >= 0) && (a_Max <= std::numeric_limits<IntType>::max()));
|
||||
Detail::cUniform<IntType> dist(IntType(0), static_cast<IntType>(a_Max));
|
||||
return static_cast<IntType>(dist(m_Engine));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random IntType in the range [0, std::numeric_limits<IntType>::max()]. */
|
||||
template <class IntType = int>
|
||||
IntType RandInt()
|
||||
{
|
||||
Detail::cUniform<IntType> dist(IntType(0), std::numeric_limits<IntType>::max());
|
||||
return static_cast<IntType>(dist(m_Engine));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random RealType in the range [a_Min, a_Max). */
|
||||
template <class RealType = float, class ArgType>
|
||||
RealType RandReal(ArgType a_Min, ArgType a_Max)
|
||||
{
|
||||
std::uniform_real_distribution<RealType> dist(a_Min, a_Max);
|
||||
return dist(m_Engine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random RealType in the range [0, a_Max). */
|
||||
template <class RealType = float, class ArgType>
|
||||
RealType RandReal(ArgType a_Max)
|
||||
{
|
||||
std::uniform_real_distribution<RealType> dist(RealType(0), a_Max);
|
||||
return dist(m_Engine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random RealType in the range [0, 1). */
|
||||
template <class RealType = float>
|
||||
RealType RandReal()
|
||||
{
|
||||
std::uniform_real_distribution<RealType> dist;
|
||||
return dist(m_Engine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Return a random bool with the given probability of being true. */
|
||||
bool RandBool(double a_TrueProbability = 0.5)
|
||||
{
|
||||
std::bernoulli_distribution dist(a_TrueProbability);
|
||||
return dist(m_Engine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Returns a reference to the underlying random engine. */
|
||||
RandomEngine & Engine()
|
||||
{
|
||||
return m_Engine;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::minstd_rand m_LinearRand;
|
||||
RandomEngine m_Engine;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class MTRand
|
||||
/** Utility to seed a random engine with maximal entropy from random_device. */
|
||||
struct cRandomDeviceSeeder
|
||||
{
|
||||
public:
|
||||
using result_type = std::random_device::result_type;
|
||||
|
||||
MTRand(void);
|
||||
|
||||
/** Returns a random integer in the range [0 .. a_Range]. */
|
||||
int randInt(int a_Range);
|
||||
|
||||
/** Returns a random integer in the range [0 .. MAX_INT]. */
|
||||
int randInt(void);
|
||||
|
||||
/** Returns a random floating point number in the range [0 .. a_Range]. */
|
||||
double rand(double a_Range);
|
||||
|
||||
private:
|
||||
|
||||
std::mt19937 m_MersenneRand;
|
||||
template <class Itr>
|
||||
void generate(Itr first, Itr last)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::uniform_int_distribution<result_type> dist;
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
*first = dist(rd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using cFastRandom = cRandomWrapper<std::minstd_rand>;
|
||||
using MTRand = cRandomWrapper<std::mt19937>;
|
||||
|
||||
/** Returns the current thread's random number source. */
|
||||
MTRand & GetRandomProvider();
|
||||
|
@ -59,8 +59,7 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a
|
||||
}
|
||||
else
|
||||
{
|
||||
MTRand rnd;
|
||||
m_Seed = rnd.randInt();
|
||||
m_Seed = GetRandomProvider().RandInt();
|
||||
LOGINFO("Chosen a new random seed for world: %d", m_Seed);
|
||||
a_IniFile.SetValueI("Seed", "Seed", m_Seed);
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ protected:
|
||||
int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1);
|
||||
int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width);
|
||||
int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width);
|
||||
cFastRandom rnd;
|
||||
auto & rnd = GetRandomProvider();
|
||||
for (int y = a_StartY; y < a_EndY; y++)
|
||||
{
|
||||
for (int z = RelStartZ; z < RelEndZ; z++)
|
||||
@ -171,7 +171,7 @@ protected:
|
||||
{
|
||||
if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z)))
|
||||
{
|
||||
BLOCKTYPE BlockType = (rnd.NextInt(101) < 75) ? a_DstBlockType1 : a_DstBlockType2;
|
||||
BLOCKTYPE BlockType = rnd.RandBool(0.75) ? a_DstBlockType1 : a_DstBlockType2;
|
||||
a_ChunkDesc.SetBlockType(x, y, z, BlockType);
|
||||
}
|
||||
} // for x
|
||||
|
26
src/Item.cpp
26
src/Item.cpp
@ -332,9 +332,9 @@ bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
||||
return false;
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
int ModifiedEnchantmentLevel = a_NumXPLevels + static_cast<int>(Random.NextFloat(static_cast<float>(Enchantability / 4))) + static_cast<int>(Random.NextFloat(static_cast<float>(Enchantability / 4))) + 1;
|
||||
float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F;
|
||||
auto & Random = GetRandomProvider();
|
||||
int ModifiedEnchantmentLevel = a_NumXPLevels + Random.RandInt(Enchantability / 4) + Random.RandInt(Enchantability / 4) + 1;
|
||||
float RandomBonus = 1.0F + (Random.RandReal() + Random.RandReal() - 1.0F) * 0.15F;
|
||||
int FinalEnchantmentLevel = static_cast<int>(ModifiedEnchantmentLevel * RandomBonus + 0.5F);
|
||||
|
||||
cWeightedEnchantments Enchantments;
|
||||
@ -352,12 +352,10 @@ bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
||||
// Checking for conflicting enchantments
|
||||
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment1);
|
||||
|
||||
float NewEnchantmentLevel = static_cast<float>(a_NumXPLevels);
|
||||
|
||||
// Next Enchantment (Second)
|
||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||
float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||
if (Enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance))
|
||||
float NewEnchantmentLevel = a_NumXPLevels / 2.0f;
|
||||
float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50.0f;
|
||||
if (Enchantments.empty() || !Random.RandBool(SecondEnchantmentChance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -370,9 +368,9 @@ bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
||||
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment2);
|
||||
|
||||
// Next Enchantment (Third)
|
||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||
float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||
if (Enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance))
|
||||
NewEnchantmentLevel = NewEnchantmentLevel / 2.0f;
|
||||
float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50.0f;
|
||||
if (Enchantments.empty() || !Random.RandBool(ThirdEnchantmentChance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -385,9 +383,9 @@ bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
||||
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment3);
|
||||
|
||||
// Next Enchantment (Fourth)
|
||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||
float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||
if (Enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance))
|
||||
NewEnchantmentLevel = NewEnchantmentLevel / 2.0f;
|
||||
float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50.0f;
|
||||
if (Enchantments.empty() || !Random.RandBool(FourthEnchantmentChance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -108,6 +108,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
if (a_Player->IsFishing())
|
||||
{
|
||||
cFloaterCallback FloaterInfo;
|
||||
@ -122,10 +124,10 @@ public:
|
||||
else if (FloaterInfo.CanPickup())
|
||||
{
|
||||
cItems Drops;
|
||||
int ItemCategory = a_World->GetTickRandomNumber(99);
|
||||
int ItemCategory = Random.RandInt(99);
|
||||
if (ItemCategory <= 4) // Treasures 5%
|
||||
{
|
||||
int Treasure = a_World->GetTickRandomNumber(5);
|
||||
int Treasure = Random.RandInt(5);
|
||||
switch (Treasure)
|
||||
{
|
||||
case 0:
|
||||
@ -140,7 +142,7 @@ public:
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, static_cast<short>(a_World->GetTickRandomNumber(50)))); // Fishing rod with durability. TODO: Enchantments on it
|
||||
Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(50))); // Fishing rod with durability. TODO: Enchantments on it
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
@ -164,14 +166,14 @@ public:
|
||||
}
|
||||
else if (ItemCategory <= 14) // Junk 10%
|
||||
{
|
||||
int Junk = a_World->GetTickRandomNumber(70);
|
||||
int Junk = Random.RandInt(70);
|
||||
if (Junk <= 1)
|
||||
{
|
||||
Drops.Add(cItem(E_ITEM_DYE, 10, 0));
|
||||
}
|
||||
else if (Junk <= 4)
|
||||
{
|
||||
Drops.Add(cItem(E_ITEM_BOW, 1, static_cast<short>(a_World->GetTickRandomNumber(64))));
|
||||
Drops.Add(cItem(E_ITEM_BOW, 1, Random.RandInt<short>(64)));
|
||||
}
|
||||
else if (Junk <= 9)
|
||||
{
|
||||
@ -214,7 +216,7 @@ public:
|
||||
}
|
||||
else // Fish
|
||||
{
|
||||
int FishType = a_World->GetTickRandomNumber(99);
|
||||
int FishType = Random.RandInt(99);
|
||||
if (FishType <= 1) // Clownfish has a 2% chance of spawning
|
||||
{
|
||||
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH));
|
||||
@ -250,7 +252,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), static_cast<int>(100 + static_cast<unsigned int>(a_World->GetTickRandomNumber(800)) - (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100)));
|
||||
cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100)));
|
||||
if (!Floater->Initialize(*a_World))
|
||||
{
|
||||
delete Floater;
|
||||
|
@ -861,8 +861,7 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
|
||||
float Chance;
|
||||
if (Success && GetEatEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance))
|
||||
{
|
||||
cFastRandom r1;
|
||||
if (r1.NextFloat() < Chance)
|
||||
if (GetRandomProvider().RandBool(Chance))
|
||||
{
|
||||
a_Player->AddEntityEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance);
|
||||
}
|
||||
|
@ -36,8 +36,7 @@ public:
|
||||
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
|
||||
|
||||
// Play sound
|
||||
cFastRandom Random;
|
||||
a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f));
|
||||
a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / GetRandomProvider().RandReal(0.8f, 1.2f));
|
||||
|
||||
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID)
|
||||
{
|
||||
|
@ -306,10 +306,8 @@ const cMapDecorator cMap::CreateDecorator(const cEntity * a_TrackedEntity)
|
||||
|
||||
if (GetDimension() == dimNether)
|
||||
{
|
||||
cFastRandom Random;
|
||||
|
||||
// TODO 2014-02-19 xdot: Refine
|
||||
Rot = Random.NextInt(16);
|
||||
Rot = GetRandomProvider().RandInt(15);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -111,12 +111,8 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
|
||||
if (allowedMobsSize > 0)
|
||||
{
|
||||
std::set<eMonsterType>::iterator itr = allowedMobs.begin();
|
||||
int iRandom = m_Random.NextInt(static_cast<int>(allowedMobsSize));
|
||||
|
||||
for (int i = 0; i < iRandom; i++)
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
std::advance(itr, GetRandomProvider().RandInt<size_t>(allowedMobsSize - 1));
|
||||
|
||||
return *itr;
|
||||
}
|
||||
@ -139,7 +135,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
|
||||
return false; // Make sure mobs do not spawn on bedrock.
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
BLOCKTYPE TargetBlock = a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ);
|
||||
|
||||
cPlayer * a_Closest_Player = a_Chunk->GetWorld()->FindClosestPlayer(a_Chunk->PositionToWorldPosition(a_RelX, a_RelY, a_RelZ), 24);
|
||||
@ -202,7 +198,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
|
||||
(BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
|
||||
) &&
|
||||
(a_RelY >= 62) &&
|
||||
(Random.NextInt(3) != 0)
|
||||
(Random.RandBool(2.0 / 3.0))
|
||||
);
|
||||
}
|
||||
|
||||
@ -260,7 +256,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
|
||||
(!cBlockInfo::IsTransparent(BlockBelow)) &&
|
||||
(SkyLight <= 7) &&
|
||||
(BlockLight <= 7) &&
|
||||
(Random.NextInt(2) == 0)
|
||||
(Random.RandBool())
|
||||
);
|
||||
}
|
||||
|
||||
@ -274,7 +270,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
|
||||
(!cBlockInfo::IsTransparent(BlockBelow)) &&
|
||||
(SkyLight <= 7) &&
|
||||
(BlockLight <= 7) &&
|
||||
(Random.NextInt(2) == 0)
|
||||
(Random.RandBool())
|
||||
);
|
||||
}
|
||||
|
||||
@ -298,7 +294,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
|
||||
(TargetBlock == E_BLOCK_AIR) &&
|
||||
(BlockAbove == E_BLOCK_AIR) &&
|
||||
(!cBlockInfo::IsTransparent(BlockBelow)) &&
|
||||
(Random.NextInt(20) == 0)
|
||||
(Random.RandBool(0.05))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "BlockID.h"
|
||||
#include "ChunkDef.h"
|
||||
#include "Chunk.h"
|
||||
#include "FastRandom.h"
|
||||
#include "Mobs/Monster.h" // This is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it
|
||||
|
||||
|
||||
@ -66,7 +65,6 @@ protected :
|
||||
bool m_NewPack;
|
||||
eMonsterType m_MobType;
|
||||
std::set<cMonster*> m_Spawned;
|
||||
cFastRandom m_Random;
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@ void cChicken::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
return; // Babies don't lay eggs
|
||||
}
|
||||
|
||||
if ((m_EggDropTimer == 6000) && (m_World->GetTickRandomNumber(1) == 0))
|
||||
if ((m_EggDropTimer == 6000) && GetRandomProvider().RandBool())
|
||||
{
|
||||
cItems Drops;
|
||||
m_EggDropTimer = 0;
|
||||
|
@ -41,16 +41,18 @@ void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
if (!m_bIsMouthOpen)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(50) == 25)
|
||||
if (Random.RandBool(0.02))
|
||||
{
|
||||
m_bIsMouthOpen = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(10) == 5)
|
||||
if (Random.RandBool(0.10))
|
||||
{
|
||||
m_bIsMouthOpen = false;
|
||||
}
|
||||
@ -60,7 +62,7 @@ void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
if (m_TameAttemptTimes < m_TimesToTame)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(50) == 25)
|
||||
if (Random.RandBool(0.02))
|
||||
{
|
||||
m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_EAST));
|
||||
m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_SMOKE, FloorC(GetPosX()), FloorC(GetPosY()), FloorC(GetPosZ()), int(SmokeDirection::SOUTH_WEST));
|
||||
|
@ -512,7 +512,7 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI)
|
||||
case mtOcelot:
|
||||
case mtWolf:
|
||||
{
|
||||
Reward = m_World->GetTickRandomNumber(2) + 1;
|
||||
Reward = GetRandomProvider().RandInt(1, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -531,7 +531,7 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI)
|
||||
case mtSlime:
|
||||
case mtMagmaCube:
|
||||
{
|
||||
Reward = 6 + (m_World->GetTickRandomNumber(2));
|
||||
Reward = GetRandomProvider().RandInt(6, 8);
|
||||
break;
|
||||
}
|
||||
case mtBlaze:
|
||||
@ -657,13 +657,15 @@ void cMonster::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
|
||||
if (m_IdleInterval > std::chrono::seconds(1))
|
||||
{
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
// At this interval the results are predictable
|
||||
int rem = m_World->GetTickRandomNumber(6) + 1;
|
||||
int rem = Random.RandInt(1, 7);
|
||||
m_IdleInterval -= std::chrono::seconds(1); // So nothing gets dropped when the server hangs for a few seconds
|
||||
|
||||
Vector3d Dist;
|
||||
Dist.x = static_cast<double>(m_World->GetTickRandomNumber(10)) - 5.0;
|
||||
Dist.z = static_cast<double>(m_World->GetTickRandomNumber(10)) - 5.0;
|
||||
Dist.x = static_cast<double>(Random.RandInt(-5, 5));
|
||||
Dist.z = static_cast<double>(Random.RandInt(-5, 5));
|
||||
|
||||
if ((Dist.SqrLength() > 2) && (rem >= 3))
|
||||
{
|
||||
@ -1005,7 +1007,7 @@ cPawn * cMonster::GetTarget ()
|
||||
|
||||
cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
|
||||
{
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
cMonster * toReturn = nullptr;
|
||||
|
||||
// Create the mob entity
|
||||
@ -1013,23 +1015,23 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
|
||||
{
|
||||
case mtMagmaCube:
|
||||
{
|
||||
toReturn = new cMagmaCube(1 << Random.NextInt(3)); // Size 1, 2 or 4
|
||||
toReturn = new cMagmaCube(1 << Random.RandInt(2)); // Size 1, 2 or 4
|
||||
break;
|
||||
}
|
||||
case mtSlime:
|
||||
{
|
||||
toReturn = new cSlime(1 << Random.NextInt(3)); // Size 1, 2 or 4
|
||||
toReturn = new cSlime(1 << Random.RandInt(2)); // Size 1, 2 or 4
|
||||
break;
|
||||
}
|
||||
case mtSkeleton:
|
||||
{
|
||||
// TODO: Actual detection of spawning in Nether
|
||||
toReturn = new cSkeleton((Random.NextInt(1) == 0) ? false : true);
|
||||
toReturn = new cSkeleton(false);
|
||||
break;
|
||||
}
|
||||
case mtVillager:
|
||||
{
|
||||
int VillagerType = Random.NextInt(6);
|
||||
int VillagerType = Random.RandInt(6);
|
||||
if (VillagerType == 6)
|
||||
{
|
||||
// Give farmers a better chance of spawning
|
||||
@ -1042,10 +1044,10 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
|
||||
case mtHorse:
|
||||
{
|
||||
// Horses take a type (species), a colour, and a style (dots, stripes, etc.)
|
||||
int HorseType = Random.NextInt(8);
|
||||
int HorseColor = Random.NextInt(7);
|
||||
int HorseStyle = Random.NextInt(5);
|
||||
int HorseTameTimes = Random.NextInt(6) + 1;
|
||||
int HorseType = Random.RandInt(7);
|
||||
int HorseColor = Random.RandInt(6);
|
||||
int HorseStyle = Random.RandInt(4);
|
||||
int HorseTameTimes = Random.RandInt(1, 6);
|
||||
|
||||
if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7))
|
||||
{
|
||||
@ -1097,11 +1099,10 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
|
||||
|
||||
void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth)
|
||||
{
|
||||
MTRand r1;
|
||||
int Count = static_cast<int>(static_cast<unsigned int>(r1.randInt()) % (a_Max + 1 - a_Min) + a_Min);
|
||||
auto Count = GetRandomProvider().RandInt<char>(static_cast<char>(a_Min), static_cast<char>(a_Max));
|
||||
if (Count > 0)
|
||||
{
|
||||
a_Drops.push_back(cItem(a_Item, static_cast<char>(Count), a_ItemHealth));
|
||||
a_Drops.emplace_back(a_Item, Count, a_ItemHealth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1111,9 +1112,7 @@ void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned
|
||||
|
||||
void cMonster::AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth)
|
||||
{
|
||||
MTRand r1;
|
||||
int Count = r1.randInt() % 1000;
|
||||
if (Count < (a_Chance * 10))
|
||||
if (GetRandomProvider().RandBool(a_Chance / 100.0))
|
||||
{
|
||||
a_Drops.push_back(cItem(a_Item, 1, a_ItemHealth));
|
||||
}
|
||||
@ -1125,11 +1124,10 @@ void cMonster::AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short
|
||||
|
||||
void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, unsigned int a_LootingLevel)
|
||||
{
|
||||
MTRand r1;
|
||||
unsigned int Count = static_cast<unsigned int>(static_cast<unsigned long>(r1.randInt()) % 200);
|
||||
if (Count < (5 + a_LootingLevel))
|
||||
auto & r1 = GetRandomProvider();
|
||||
if (r1.RandBool((5 + a_LootingLevel) / 200.0))
|
||||
{
|
||||
size_t Rare = static_cast<size_t>(r1.randInt()) % a_Items.Size();
|
||||
size_t Rare = r1.RandInt<size_t>(a_Items.Size() - 1);
|
||||
a_Drops.push_back(a_Items.at(Rare));
|
||||
}
|
||||
}
|
||||
@ -1140,8 +1138,11 @@ void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, unsigne
|
||||
|
||||
void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
|
||||
{
|
||||
MTRand r1;
|
||||
if (r1.randInt() % 200 < ((m_DropChanceHelmet * 200) + (a_LootingLevel * 2)))
|
||||
auto & r1 = GetRandomProvider();
|
||||
|
||||
double LootingBonus = a_LootingLevel / 100.0;
|
||||
|
||||
if (r1.RandBool(m_DropChanceHelmet + LootingBonus))
|
||||
{
|
||||
if (!GetEquippedHelmet().IsEmpty())
|
||||
{
|
||||
@ -1149,7 +1150,7 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLe
|
||||
}
|
||||
}
|
||||
|
||||
if (r1.randInt() % 200 < ((m_DropChanceChestplate * 200) + (a_LootingLevel * 2)))
|
||||
if (r1.RandBool(m_DropChanceChestplate + LootingBonus))
|
||||
{
|
||||
if (!GetEquippedChestplate().IsEmpty())
|
||||
{
|
||||
@ -1157,7 +1158,7 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLe
|
||||
}
|
||||
}
|
||||
|
||||
if (r1.randInt() % 200 < ((m_DropChanceLeggings * 200) + (a_LootingLevel * 2)))
|
||||
if (r1.RandBool(m_DropChanceLeggings + LootingBonus))
|
||||
{
|
||||
if (!GetEquippedLeggings().IsEmpty())
|
||||
{
|
||||
@ -1165,7 +1166,7 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLe
|
||||
}
|
||||
}
|
||||
|
||||
if (r1.randInt() % 200 < ((m_DropChanceBoots * 200) + (a_LootingLevel * 2)))
|
||||
if (r1.RandBool(m_DropChanceBoots + LootingBonus))
|
||||
{
|
||||
if (!GetEquippedBoots().IsEmpty())
|
||||
{
|
||||
@ -1180,8 +1181,7 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLe
|
||||
|
||||
void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
|
||||
{
|
||||
MTRand r1;
|
||||
if (r1.randInt() % 200 < ((m_DropChanceWeapon * 200) + (a_LootingLevel * 2)))
|
||||
if (GetRandomProvider().RandBool(m_DropChanceWeapon + (a_LootingLevel / 100.0)))
|
||||
{
|
||||
if (!GetEquippedWeapon().IsEmpty())
|
||||
{
|
||||
|
@ -127,8 +127,7 @@ void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
Callback.Baby->InheritFromParents(this, m_LovePartner);
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, 1 + Random.NextInt(6));
|
||||
m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6));
|
||||
|
||||
m_LovePartner->ResetLoveMode();
|
||||
ResetLoveMode();
|
||||
|
@ -148,7 +148,7 @@ bool cPath::StepOnce()
|
||||
// Check if we have a new NearestPoint.
|
||||
if ((m_Destination - CurrentCell->m_Location).Length() < 5)
|
||||
{
|
||||
if (m_Rand.NextInt(4) == 0)
|
||||
if (GetRandomProvider().RandBool(0.25))
|
||||
{
|
||||
m_NearestPointToTarget = CurrentCell;
|
||||
}
|
||||
|
@ -178,7 +178,6 @@ private:
|
||||
double m_HalfWidth;
|
||||
int m_StepsLeft;
|
||||
cPathCell * m_NearestPointToTarget;
|
||||
cFastRandom m_Rand;
|
||||
|
||||
/* Control fields */
|
||||
ePathFinderStatus m_Status;
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
|
||||
cRabbit::cRabbit(void) :
|
||||
cRabbit(static_cast<eRabbitType>(cFastRandom().NextInt(
|
||||
static_cast<UInt8>(eRabbitType::SaltAndPepper) + 1 // Max possible Rabbit-Type
|
||||
cRabbit(static_cast<eRabbitType>(GetRandomProvider().RandInt<UInt8>(
|
||||
static_cast<UInt8>(eRabbitType::SaltAndPepper) // Max possible Rabbit-Type
|
||||
)), 0)
|
||||
{
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
|
||||
a_Player.UseEquippedItem();
|
||||
|
||||
cItems Drops;
|
||||
int NumDrops = m_World->GetTickRandomNumber(2) + 1;
|
||||
Drops.push_back(cItem(E_BLOCK_WOOL, static_cast<char>(NumDrops), static_cast<short>(m_WoolColor)));
|
||||
char NumDrops = GetRandomProvider().RandInt<char>(1, 3);
|
||||
Drops.emplace_back(E_BLOCK_WOOL, NumDrops, static_cast<short>(m_WoolColor));
|
||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||
m_World->BroadcastSoundEffect("entity.sheep.shear", GetPosX(), GetPosY(), GetPosZ(), 1.0f, 1.0f);
|
||||
}
|
||||
@ -121,7 +121,7 @@ void cSheep::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(600) == 1)
|
||||
if (GetRandomProvider().RandBool(1.0 / 600.0))
|
||||
{
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
|
||||
{
|
||||
@ -167,8 +167,7 @@ void cSheep::InheritFromParents(cPassiveMonster * a_Parent1, cPassiveMonster * a
|
||||
return;
|
||||
}
|
||||
}
|
||||
cFastRandom Random;
|
||||
SetFurColor((Random.NextInt(100) < 50) ? Parent1->GetFurColor() : Parent2->GetFurColor());
|
||||
SetFurColor(GetRandomProvider().RandBool() ? Parent1->GetFurColor() : Parent2->GetFurColor());
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
|
||||
@ -178,8 +177,7 @@ void cSheep::InheritFromParents(cPassiveMonster * a_Parent1, cPassiveMonster * a
|
||||
|
||||
NIBBLETYPE cSheep::GenerateNaturalRandomColor(void)
|
||||
{
|
||||
cFastRandom Random;
|
||||
int Chance = Random.NextInt(101);
|
||||
int Chance = GetRandomProvider().RandInt(100);
|
||||
|
||||
if (Chance <= 81)
|
||||
{
|
||||
|
@ -51,12 +51,12 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||
bool cSkeleton::Attack(std::chrono::milliseconds a_Dt)
|
||||
{
|
||||
StopMovingToPosition(); // Todo handle this in a better way, the skeleton does some uneeded recalcs due to inStateChasing
|
||||
cFastRandom Random;
|
||||
auto & Random = GetRandomProvider();
|
||||
if ((GetTarget() != nullptr) && (m_AttackCoolDownTicksLeft == 0))
|
||||
{
|
||||
Vector3d Inaccuracy = Vector3d(Random.NextFloat(0.5) - 0.25, Random.NextFloat(0.5) - 0.25, Random.NextFloat(0.5) - 0.25);
|
||||
Vector3d Inaccuracy = Vector3d(Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25));
|
||||
Vector3d Speed = (GetTarget()->GetPosition() + Inaccuracy - GetPosition()) * 5;
|
||||
Speed.y = Speed.y - 1 + Random.NextInt(3);
|
||||
Speed.y += Random.RandInt(-1, 1);
|
||||
cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed);
|
||||
if (Arrow == nullptr)
|
||||
{
|
||||
|
@ -70,8 +70,8 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI)
|
||||
|
||||
if (m_Size != 1)
|
||||
{
|
||||
cFastRandom Random;
|
||||
int SpawnAmount = 2 + Random.NextInt(3);
|
||||
auto & Random = GetRandomProvider();
|
||||
int SpawnAmount = Random.RandInt(2, 4);
|
||||
|
||||
for (int i = 0; i < SpawnAmount; ++i)
|
||||
{
|
||||
@ -80,7 +80,7 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI)
|
||||
|
||||
cSlime * NewSlime = new cSlime(m_Size / 2);
|
||||
NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ);
|
||||
NewSlime->SetYaw(Random.NextFloat(1.0f) * 360.0f);
|
||||
NewSlime->SetYaw(Random.RandReal(360.0f));
|
||||
m_World->SpawnMobFinalize(NewSlime);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPlayer())
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(5) == 3)
|
||||
if (GetRandomProvider().RandBool(1.0 / 6.0))
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
||||
}
|
||||
@ -90,7 +90,7 @@ void cVillager::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
|
||||
// Don't always try to do a special action. Each tick has 1% to do a special action.
|
||||
if (m_World->GetTickRandomNumber(99) != 0)
|
||||
if (GetRandomProvider().RandBool(0.99))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -150,7 +150,7 @@ void cVillager::HandleFarmerPrepareFarmCrops()
|
||||
|
||||
m_VillagerAction = true;
|
||||
m_CropsPos = Vector3i(static_cast<int>(GetPosX()) + X - 5, static_cast<int>(GetPosY()) + Y - 3, static_cast<int>(GetPosZ()) + Z - 5);
|
||||
MoveToPosition(Vector3f(static_cast<float>(m_CropsPos.x + 0.5), static_cast<float>(m_CropsPos.y), static_cast<float>(m_CropsPos.z + 0.5)));
|
||||
MoveToPosition(Vector3d(m_CropsPos.x + 0.5, m_CropsPos.y + 0.0, m_CropsPos.z + 0.5));
|
||||
return;
|
||||
} // for Y loop.
|
||||
} // Repeat the procces 5 times.
|
||||
|
@ -24,11 +24,11 @@ void cWitch::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||
{
|
||||
LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
|
||||
}
|
||||
MTRand r1;
|
||||
int DropTypeCount = (r1.randInt() % 3) + 1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
int DropTypeCount = r1.RandInt(1, 3);
|
||||
for (int i = 0; i < DropTypeCount; i++)
|
||||
{
|
||||
int DropType = r1.randInt() % 7;
|
||||
int DropType = r1.RandInt(6);
|
||||
switch (DropType)
|
||||
{
|
||||
case 0: AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GLASS_BOTTLE); break;
|
||||
|
@ -138,7 +138,7 @@ void cWolf::ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool
|
||||
// If a player is asking for help and we already have a target,
|
||||
// there's a 50% chance of helping and a 50% chance of doing nothing
|
||||
// This helps spread a wolf pack's targets over several mobs
|
||||
else if (m_World->GetTickRandomNumber(9)> 4)
|
||||
else if (GetRandomProvider().RandBool())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -179,7 +179,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
|
||||
a_Player.GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
if (m_World->GetTickRandomNumber(7) == 0)
|
||||
if (GetRandomProvider().RandBool(0.125))
|
||||
{
|
||||
// Taming succeeded
|
||||
SetMaxHealth(20);
|
||||
|
@ -100,8 +100,7 @@ bool cProbabDistrib::SetDefString(const AString & a_DefString)
|
||||
|
||||
int cProbabDistrib::Random(MTRand & a_Rand) const
|
||||
{
|
||||
int v = a_Rand.randInt(m_Sum);
|
||||
return MapValue(v);
|
||||
return MapValue(a_Rand.RandInt(m_Sum));
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,8 +20,7 @@ Usage:
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class MTRand;
|
||||
#include "FastRandom.h"
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "WebAdmin.h"
|
||||
#include "Protocol/ProtocolRecognizer.h"
|
||||
#include "CommandOutput.h"
|
||||
#include "FastRandom.h"
|
||||
|
||||
#include "IniFile.h"
|
||||
#include "Vector3.h"
|
||||
@ -218,9 +219,9 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul
|
||||
m_ShouldAuthenticate = a_ShouldAuth;
|
||||
if (m_ShouldAuthenticate)
|
||||
{
|
||||
MTRand mtrand1;
|
||||
unsigned int r1 = (mtrand1.randInt() % 1147483647) + 1000000000;
|
||||
unsigned int r2 = (mtrand1.randInt() % 1147483647) + 1000000000;
|
||||
auto & rand = GetRandomProvider();
|
||||
unsigned int r1 = rand.RandInt<unsigned int>(1000000000U, 0x7fffffffU);
|
||||
unsigned int r2 = rand.RandInt<unsigned int>(1000000000U, 0x7fffffffU);
|
||||
std::ostringstream sid;
|
||||
sid << std::hex << r1;
|
||||
sid << std::hex << r2;
|
||||
|
@ -301,7 +301,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in
|
||||
void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||
{
|
||||
/*
|
||||
if (m_World.GetTickRandomNumber(10000) > 100)
|
||||
if (GetRandomProvider().RandBool(0.99))
|
||||
{
|
||||
// Make the chance to spread 100x smaller
|
||||
return;
|
||||
@ -317,7 +317,7 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int
|
||||
// No need to check the coords for equality with the parent block,
|
||||
// it cannot catch fire anyway (because it's not an air block)
|
||||
|
||||
if (m_World.GetTickRandomNumber(MAX_CHANCE_FLAMMABILITY) > m_Flammability)
|
||||
if (!GetRandomProvider().RandBool(m_Flammability * (1.0 / MAX_CHANCE_FLAMMABILITY)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -381,7 +381,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
|
||||
return;
|
||||
}
|
||||
|
||||
bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance);
|
||||
bool ShouldReplaceFuel = (GetRandomProvider().RandBool(m_ReplaceFuelChance * (1.0 / MAX_CHANCE_REPLACE_FUEL)));
|
||||
if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, AbsX, Y, AbsZ, ssFireSpread))
|
||||
{
|
||||
Neighbour->SetBlock(X, Y, Z, E_BLOCK_FIRE, 0);
|
||||
|
@ -1003,8 +1003,7 @@ void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player)
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_Player.GetWorld()->GetBlockTypeMeta(PosX, PosY, PosZ, Block, BlockMeta);
|
||||
|
||||
cFastRandom Random;
|
||||
if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && (Random.NextFloat(1.0F) < 0.12F))
|
||||
if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && GetRandomProvider().RandBool(0.12))
|
||||
{
|
||||
NIBBLETYPE Orientation = BlockMeta & 0x3;
|
||||
NIBBLETYPE AnvilDamage = BlockMeta >> 2;
|
||||
@ -1578,8 +1577,8 @@ void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
|
||||
{
|
||||
int Bookshelves = std::min(GetBookshelvesCount(*a_Player.GetWorld()), 15);
|
||||
|
||||
cFastRandom Random;
|
||||
int Base = (Random.GenerateRandomInteger(1, 8) + static_cast<int>(floor(static_cast<float>(Bookshelves / 2)) + Random.GenerateRandomInteger(0, Bookshelves)));
|
||||
auto & Random = GetRandomProvider();
|
||||
int Base = (Random.RandInt(1, 8) + (Bookshelves / 2) + Random.RandInt(0, Bookshelves));
|
||||
int TopSlot = std::max(Base / 3, 1);
|
||||
int MiddleSlot = (Base * 2) / 3 + 1;
|
||||
int BottomSlot = std::max(Base, Bookshelves * 2);
|
||||
|
@ -245,22 +245,20 @@ void cWorld::CastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
|
||||
int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
|
||||
{
|
||||
auto & Random = GetRandomProvider();
|
||||
switch (a_Weather)
|
||||
{
|
||||
case eWeather_Sunny:
|
||||
{
|
||||
auto dif = m_MaxSunnyTicks - m_MinSunnyTicks + 1;
|
||||
return m_MinSunnyTicks + (m_TickRand.randInt() % dif);
|
||||
return Random.RandInt(m_MinSunnyTicks, m_MaxSunnyTicks);
|
||||
}
|
||||
case eWeather_Rain:
|
||||
{
|
||||
auto dif = m_MaxRainTicks - m_MinRainTicks + 1;
|
||||
return m_MinRainTicks + (m_TickRand.randInt() % dif);
|
||||
return Random.RandInt(m_MinRainTicks, m_MaxRainTicks);
|
||||
}
|
||||
case eWeather_ThunderStorm:
|
||||
{
|
||||
auto dif = m_MaxThunderStormTicks - m_MinThunderStormTicks + 1;
|
||||
return m_MinThunderStormTicks + (m_TickRand.randInt() % dif);
|
||||
return Random.RandInt(m_MinThunderStormTicks, m_MaxThunderStormTicks);
|
||||
}
|
||||
}
|
||||
|
||||
@ -812,7 +810,7 @@ eWeather cWorld::ChooseNewWeather()
|
||||
case eWeather_Rain:
|
||||
{
|
||||
// 1 / 8 chance of turning into a thunderstorm
|
||||
return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
|
||||
return GetRandomProvider().RandBool(0.125) ? eWeather_ThunderStorm : eWeather_Sunny;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1074,7 +1072,7 @@ void cWorld::TickWeather(float a_Dt)
|
||||
if (m_Weather == eWeather_ThunderStorm)
|
||||
{
|
||||
// 0.5% chance per tick of thunderbolt
|
||||
if (m_TickRand.randInt() % 199 == 0)
|
||||
if (GetRandomProvider().RandBool(0.005))
|
||||
{
|
||||
CastThunderbolt(0, 0, 0); // TODO: find random positions near players to cast thunderbolts.
|
||||
}
|
||||
@ -1697,7 +1695,7 @@ void cWorld::GrowTreeImage(const sSetBlockVector & a_Blocks)
|
||||
|
||||
bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal)
|
||||
{
|
||||
cFastRandom random;
|
||||
auto & random = GetRandomProvider();
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1735,7 +1733,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockMeta += random.NextInt(4) + 2;
|
||||
BlockMeta += random.RandInt(2, 5);
|
||||
BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
|
||||
}
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1770,7 +1768,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockMeta += random.NextInt(4) + 2;
|
||||
BlockMeta += random.RandInt(2, 5);
|
||||
BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
|
||||
}
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1793,7 +1791,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockMeta += random.NextInt(4) + 2;
|
||||
BlockMeta += random.RandInt(2, 5);
|
||||
BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
|
||||
}
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1825,7 +1823,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockMeta += random.NextInt(4) + 2;
|
||||
BlockMeta += random.RandInt(2, 5);
|
||||
BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
|
||||
}
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1848,7 +1846,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockMeta += random.NextInt(4) + 2;
|
||||
BlockMeta += random.RandInt(2, 5);
|
||||
BlockMeta = std::min(BlockMeta, static_cast<NIBBLETYPE>(7));
|
||||
}
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
@ -1884,14 +1882,14 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
{
|
||||
++GrowState;
|
||||
}
|
||||
else if (random.NextInt(99) < 45)
|
||||
else if (random.RandBool(0.45))
|
||||
{
|
||||
++GrowState;
|
||||
}
|
||||
|
||||
FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, static_cast<NIBBLETYPE>(GrowState << 3 | TypeMeta));
|
||||
}
|
||||
else if (random.NextInt(99) < 45)
|
||||
else if (random.RandBool(0.45))
|
||||
{
|
||||
GrowTreeFromSapling(a_BlockX, a_BlockY, a_BlockZ, BlockMeta);
|
||||
}
|
||||
@ -1905,12 +1903,12 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MTRand r1;
|
||||
auto & r1 = GetRandomProvider();
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
int OfsX = static_cast<int>(r1.randInt(3) + r1.randInt(3) + r1.randInt(3) + r1.randInt(3)) / 2 - 3;
|
||||
int OfsY = static_cast<int>(r1.randInt(3) + r1.randInt(3)) - 3;
|
||||
int OfsZ = static_cast<int>(r1.randInt(3) + r1.randInt(3) + r1.randInt(3) + r1.randInt(3)) / 2 - 3;
|
||||
int OfsX = (r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3)) / 2 - 3;
|
||||
int OfsY = r1.RandInt(3) + r1.RandInt(3) - 3;
|
||||
int OfsZ = (r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3) + r1.RandInt(3)) / 2 - 3;
|
||||
BLOCKTYPE Ground = GetBlock(a_BlockX + OfsX, a_BlockY + OfsY, a_BlockZ + OfsZ);
|
||||
if (Ground != E_BLOCK_GRASS)
|
||||
{
|
||||
@ -1923,7 +1921,7 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy
|
||||
}
|
||||
BLOCKTYPE SpawnType;
|
||||
NIBBLETYPE SpawnMeta = 0;
|
||||
switch (r1.randInt(10))
|
||||
switch (r1.RandInt(10))
|
||||
{
|
||||
case 0: SpawnType = E_BLOCK_YELLOW_FLOWER; break;
|
||||
case 1: SpawnType = E_BLOCK_RED_ROSE; break;
|
||||
@ -2031,8 +2029,7 @@ int cWorld::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocks
|
||||
|
||||
bool cWorld::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
|
||||
{
|
||||
MTRand Rand;
|
||||
return m_ChunkMap->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, Rand);
|
||||
return m_ChunkMap->GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
|
||||
}
|
||||
|
||||
|
||||
@ -2162,6 +2159,7 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
|
||||
|
||||
void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated)
|
||||
{
|
||||
auto & Random = GetRandomProvider();
|
||||
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
|
||||
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
|
||||
{
|
||||
@ -2171,9 +2169,9 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
|
||||
continue;
|
||||
}
|
||||
|
||||
float SpeedX = static_cast<float>(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
|
||||
float SpeedY = static_cast<float>(a_FlyAwaySpeed * GetTickRandomNumber(50));
|
||||
float SpeedZ = static_cast<float>(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
|
||||
float SpeedX = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-5, 5));
|
||||
float SpeedY = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(50));
|
||||
float SpeedZ = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-5, 5));
|
||||
|
||||
cPickup * Pickup = new cPickup(
|
||||
a_BlockX, a_BlockY, a_BlockZ,
|
||||
@ -2310,10 +2308,11 @@ UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTick
|
||||
TNT = nullptr;
|
||||
return cEntity::INVALID_ID;
|
||||
}
|
||||
auto & Random = GetRandomProvider();
|
||||
TNT->SetSpeed(
|
||||
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
|
||||
a_InitialVelocityCoeff * Random.RandInt(-1, 1),
|
||||
a_InitialVelocityCoeff * 2,
|
||||
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1)
|
||||
a_InitialVelocityCoeff * Random.RandInt(-1, 1)
|
||||
);
|
||||
return TNT->GetUniqueID();
|
||||
}
|
||||
@ -3793,6 +3792,15 @@ UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cPr
|
||||
|
||||
|
||||
|
||||
int cWorld::GetTickRandomNumber(int a_Range)
|
||||
{
|
||||
return GetRandomProvider().RandInt(a_Range);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results)
|
||||
{
|
||||
typedef std::pair<AString::size_type, AString> pair_t;
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "MapManager.h"
|
||||
#include "Blocks/WorldInterface.h"
|
||||
#include "Blocks/BroadcastInterface.h"
|
||||
#include "FastRandom.h"
|
||||
#include "EffectID.h"
|
||||
|
||||
|
||||
@ -801,8 +800,8 @@ public:
|
||||
Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */
|
||||
UInt32 CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed = nullptr); // tolua_export
|
||||
|
||||
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
|
||||
int GetTickRandomNumber(int a_Range) { return static_cast<int>(m_TickRand.randInt(a_Range)); }
|
||||
/** Returns a random number in range [0 .. a_Range]. */
|
||||
int GetTickRandomNumber(int a_Range);
|
||||
|
||||
/** Appends all usernames starting with a_Text (case-insensitive) into Results */
|
||||
void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
|
||||
@ -880,9 +879,6 @@ private:
|
||||
/** The dimension of the world, used by the client to provide correct lighting scheme */
|
||||
eDimension m_Dimension;
|
||||
|
||||
/** This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) */
|
||||
MTRand m_TickRand;
|
||||
|
||||
bool m_IsSpawnExplicitlySet;
|
||||
double m_SpawnX;
|
||||
double m_SpawnY;
|
||||
|
@ -15,14 +15,13 @@ static void TestInts(void)
|
||||
cFastRandom rnd;
|
||||
int sum = 0;
|
||||
const int BUCKETS = 8;
|
||||
int Counts[BUCKETS];
|
||||
memset(Counts, 0, sizeof(Counts));
|
||||
int Counts[BUCKETS] = {0};
|
||||
const int ITER = 10000;
|
||||
for (int i = 0; i < ITER; i++)
|
||||
{
|
||||
int v = rnd.NextInt(1000);
|
||||
int v = rnd.RandInt(1000);
|
||||
assert_test(v >= 0);
|
||||
assert_test(v < 1000);
|
||||
assert_test(v <= 1000);
|
||||
Counts[v % BUCKETS]++;
|
||||
sum += v;
|
||||
}
|
||||
@ -43,12 +42,11 @@ static void TestFloats(void)
|
||||
cFastRandom rnd;
|
||||
float sum = 0;
|
||||
const int BUCKETS = 8;
|
||||
int Counts[BUCKETS];
|
||||
memset(Counts, 0, sizeof(Counts));
|
||||
int Counts[BUCKETS] = {0};
|
||||
const int ITER = 10000;
|
||||
for (int i = 0; i < ITER; i++)
|
||||
{
|
||||
float v = rnd.NextFloat(1000);
|
||||
float v = rnd.RandReal(1000.0f);
|
||||
assert_test(v >= 0);
|
||||
assert_test(v <= 1000);
|
||||
Counts[static_cast<int>(v) % BUCKETS]++;
|
||||
@ -76,7 +74,7 @@ static void TestReCreation(void)
|
||||
for (int i = 0; i < ITER; ++i)
|
||||
{
|
||||
cFastRandom rnd;
|
||||
int val = rnd.NextInt(10);
|
||||
int val = rnd.RandInt(9);
|
||||
if (val == lastVal)
|
||||
{
|
||||
numSame += 1;
|
||||
|
Loading…
Reference in New Issue
Block a user