1
0
Fork 0
cuberite-2a/src/Mobs/Villager.cpp

214 lines
4.2 KiB
C++
Raw Normal View History

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Villager.h"
#include "../World.h"
2014-01-27 18:06:50 +00:00
#include "../BlockArea.h"
2014-01-27 13:40:31 +00:00
#include "../Blocks/BlockHandler.h"
2014-02-02 14:49:37 +00:00
#include "../BlockInServerPluginInterface.h"
cVillager::cVillager(eVillagerType VillagerType) :
2017-02-15 05:05:24 +00:00
super("Villager", mtVillager, "entity.villager.hurt", "entity.villager.death", 0.6, 1.8),
2014-02-05 17:43:49 +00:00
m_ActionCountDown(-1),
2014-01-27 13:40:31 +00:00
m_Type(VillagerType),
2014-02-05 17:43:49 +00:00
m_VillagerAction(false)
{
}
2014-04-25 22:32:30 +00:00
bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{
2014-04-25 22:32:30 +00:00
if (!super::DoTakeDamage(a_TDI))
{
return false;
}
2014-10-20 20:55:07 +00:00
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPlayer())
{
2017-06-13 19:35:30 +00:00
if (GetRandomProvider().RandBool(1.0 / 6.0))
{
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
}
}
2014-11-22 07:58:35 +00:00
if (a_TDI.DamageType == dtLightning)
{
Destroy();
2015-07-16 13:06:54 +00:00
m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtWitch, false);
2014-11-22 07:58:35 +00:00
return true;
}
2014-04-25 22:32:30 +00:00
return true;
}
2014-01-27 13:40:31 +00:00
void cVillager::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
2014-01-27 13:40:31 +00:00
{
super::Tick(a_Dt, a_Chunk);
if (!IsTicking())
{
// The base class tick destroyed us
return;
}
if (m_ActionCountDown > -1)
{
m_ActionCountDown--;
if (m_ActionCountDown == 0)
{
switch (m_Type)
{
2014-07-17 20:50:58 +00:00
case vtFarmer:
{
HandleFarmerPlaceCrops();
}
}
}
return;
}
if (m_VillagerAction)
2014-01-27 13:40:31 +00:00
{
switch (m_Type)
2014-01-27 13:40:31 +00:00
{
case vtFarmer:
{
HandleFarmerTryHarvestCrops();
}
2014-01-27 13:40:31 +00:00
}
m_VillagerAction = false;
return;
}
// Don't always try to do a special action. Each tick has 1% to do a special action.
2017-06-13 19:35:30 +00:00
if (GetRandomProvider().RandBool(0.99))
2014-01-27 13:40:31 +00:00
{
return;
}
switch (m_Type)
{
case vtFarmer:
{
HandleFarmerPrepareFarmCrops();
2014-01-27 13:40:31 +00:00
}
}
}
2014-01-27 20:39:00 +00:00
////////////////////////////////////////////////////////////////////////////////
2015-07-31 14:49:10 +00:00
// Farmer functions:
void cVillager::HandleFarmerPrepareFarmCrops()
2014-01-27 13:40:31 +00:00
{
if (!m_World->VillagersShouldHarvestCrops())
{
return;
}
2014-01-27 13:40:31 +00:00
cBlockArea Surrounding;
2015-07-31 14:49:10 +00:00
// Read a 11x7x11 area:
Surrounding.Read(
*m_World,
2015-07-31 14:49:10 +00:00
FloorC(GetPosX()) - 5,
FloorC(GetPosX()) + 6,
FloorC(GetPosY()) - 3,
FloorC(GetPosY()) + 4,
FloorC(GetPosZ()) - 5,
FloorC(GetPosZ()) + 6
);
2014-01-27 13:40:31 +00:00
for (int I = 0; I < 5; I++)
2014-01-27 13:40:31 +00:00
{
for (int Y = 0; Y < 6; Y++)
{
// Pick random coordinates and check for crops.
int X = m_World->GetTickRandomNumber(11);
int Z = m_World->GetTickRandomNumber(11);
2014-01-27 20:39:00 +00:00
// A villager can't farm this.
if (!IsBlockFarmable(Surrounding.GetRelBlockType(X, Y, Z)))
2014-01-27 13:40:31 +00:00
{
continue;
2014-01-27 13:40:31 +00:00
}
if (Surrounding.GetRelBlockMeta(X, Y, Z) != 0x7)
{
continue;
}
m_VillagerAction = true;
m_CropsPos = Vector3i(static_cast<int>(GetPosX()) + X - 5, static_cast<int>(GetPosY()) + Y - 3, static_cast<int>(GetPosZ()) + Z - 5);
2017-06-13 19:35:30 +00:00
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.
2014-01-27 13:40:31 +00:00
}
void cVillager::HandleFarmerTryHarvestCrops()
{
2014-01-27 20:39:00 +00:00
// Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
if (!m_PathfinderActivated && (GetPosition() - m_CropsPos).Length() < 2)
{
2014-01-27 20:39:00 +00:00
// Check if the blocks didn't change while the villager was walking to the coordinates.
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7)
{
cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock);
2014-02-02 14:49:37 +00:00
cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World);
Handler->DropBlock(ChunkInterface, *m_World, PluginInterface, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_AIR, 0);
m_ActionCountDown = 20;
}
}
}
void cVillager::HandleFarmerPlaceCrops()
{
2014-01-27 20:39:00 +00:00
// Check if there is still farmland at the spot where the crops were.
if (m_World->GetBlock(m_CropsPos.x, m_CropsPos.y - 1, m_CropsPos.z) == E_BLOCK_FARMLAND)
{
m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_CROPS, 0);
}
}
bool cVillager::IsBlockFarmable(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
{
2017-02-14 10:13:55 +00:00
case E_BLOCK_BEETROOTS:
case E_BLOCK_CROPS:
case E_BLOCK_POTATOES:
case E_BLOCK_CARROTS:
{
return true;
}
}
return false;
}