2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
|
|
|
|
|
|
#include "Villager.h"
|
2013-10-08 14:20:49 -04:00
|
|
|
#include "../World.h"
|
2014-01-27 13:06:50 -05:00
|
|
|
#include "../BlockArea.h"
|
2014-01-27 08:40:31 -05:00
|
|
|
#include "../Blocks/BlockHandler.h"
|
2014-02-02 09:49:37 -05:00
|
|
|
#include "../BlockInServerPluginInterface.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-11 15:57:22 -04:00
|
|
|
cVillager::cVillager(eVillagerType VillagerType) :
|
2013-10-20 04:23:30 -04:00
|
|
|
super("Villager", mtVillager, "", "", 0.6, 1.8),
|
2014-02-05 12:43:49 -05:00
|
|
|
m_ActionCountDown(-1),
|
2014-01-27 08:40:31 -05:00
|
|
|
m_Type(VillagerType),
|
2014-02-05 12:43:49 -05:00
|
|
|
m_VillagerAction(false)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-08 14:20:49 -04:00
|
|
|
|
2014-04-25 18:32:30 -04:00
|
|
|
bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
2013-10-08 14:20:49 -04:00
|
|
|
{
|
2014-04-25 18:32:30 -04:00
|
|
|
if (!super::DoTakeDamage(a_TDI))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-25 19:14:00 -05:00
|
|
|
if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
|
2013-10-08 14:20:49 -04:00
|
|
|
{
|
|
|
|
if (m_World->GetTickRandomNumber(5) == 3)
|
|
|
|
{
|
2014-04-12 08:16:48 -04:00
|
|
|
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
2013-10-08 14:20:49 -04:00
|
|
|
}
|
|
|
|
}
|
2014-04-25 18:32:30 -04:00
|
|
|
return true;
|
2013-10-08 14:20:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-27 08:40:31 -05:00
|
|
|
|
|
|
|
void cVillager::Tick(float a_Dt, cChunk & a_Chunk)
|
|
|
|
{
|
|
|
|
super::Tick(a_Dt, a_Chunk);
|
2014-01-28 10:26:44 -05:00
|
|
|
|
2014-01-27 12:27:57 -05:00
|
|
|
if (m_ActionCountDown > -1)
|
|
|
|
{
|
|
|
|
m_ActionCountDown--;
|
|
|
|
if (m_ActionCountDown == 0)
|
|
|
|
{
|
|
|
|
switch (m_Type)
|
|
|
|
{
|
2014-07-17 16:50:58 -04:00
|
|
|
case vtFarmer:
|
2014-01-27 14:44:18 -05:00
|
|
|
{
|
2014-01-28 10:26:44 -05:00
|
|
|
HandleFarmerPlaceCrops();
|
2014-01-27 14:44:18 -05:00
|
|
|
}
|
2014-01-27 12:27:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-27 15:34:22 -05:00
|
|
|
if (m_VillagerAction)
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
2014-01-27 15:34:22 -05:00
|
|
|
switch (m_Type)
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
2014-01-27 15:34:22 -05:00
|
|
|
case vtFarmer:
|
2014-01-27 09:44:55 -05:00
|
|
|
{
|
2014-01-28 10:26:44 -05:00
|
|
|
HandleFarmerTryHarvestCrops();
|
2014-01-27 09:44:55 -05:00
|
|
|
}
|
2014-01-27 08:40:31 -05:00
|
|
|
}
|
2014-01-27 15:34:22 -05:00
|
|
|
m_VillagerAction = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't always try to do a special action. Each tick has 1% to do a special action.
|
|
|
|
if (m_World->GetTickRandomNumber(99) != 0)
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (m_Type)
|
|
|
|
{
|
|
|
|
case vtFarmer:
|
|
|
|
{
|
2014-01-28 10:26:44 -05:00
|
|
|
HandleFarmerPrepareFarmCrops();
|
2014-01-27 08:40:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-27 15:39:00 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Farmer functions.
|
2014-01-28 10:26:44 -05:00
|
|
|
void cVillager::HandleFarmerPrepareFarmCrops()
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
2014-01-27 16:04:24 -05:00
|
|
|
if (!m_World->VillagersShouldHarvestCrops())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-27 08:40:31 -05:00
|
|
|
cBlockArea Surrounding;
|
2014-01-27 15:34:22 -05:00
|
|
|
/// Read a 11x7x11 area.
|
|
|
|
Surrounding.Read(
|
|
|
|
m_World,
|
|
|
|
(int) GetPosX() - 5,
|
|
|
|
(int) GetPosX() + 5,
|
|
|
|
(int) GetPosY() - 3,
|
|
|
|
(int) GetPosY() + 3,
|
|
|
|
(int) GetPosZ() - 5,
|
|
|
|
(int) GetPosZ() + 5
|
|
|
|
);
|
2014-01-27 08:40:31 -05:00
|
|
|
|
2014-01-27 12:58:09 -05:00
|
|
|
for (int I = 0; I < 5; I++)
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
|
|
|
for (int Y = 0; Y < 6; Y++)
|
|
|
|
{
|
2014-01-27 12:58:09 -05:00
|
|
|
// Pick random coordinates and check for crops.
|
|
|
|
int X = m_World->GetTickRandomNumber(11);
|
|
|
|
int Z = m_World->GetTickRandomNumber(11);
|
|
|
|
|
2014-01-27 15:39:00 -05:00
|
|
|
// A villager can't farm this.
|
2014-01-27 12:58:09 -05:00
|
|
|
if (!IsBlockFarmable(Surrounding.GetRelBlockType(X, Y, Z)))
|
2014-01-27 08:40:31 -05:00
|
|
|
{
|
2014-01-27 12:58:09 -05:00
|
|
|
continue;
|
2014-01-27 08:40:31 -05:00
|
|
|
}
|
2014-01-27 12:58:09 -05:00
|
|
|
if (Surrounding.GetRelBlockMeta(X, Y, Z) != 0x7)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-27 15:34:22 -05:00
|
|
|
m_VillagerAction = true;
|
2014-01-27 12:58:09 -05:00
|
|
|
m_CropsPos = Vector3i((int) GetPosX() + X - 5, (int) GetPosY() + Y - 3, (int) GetPosZ() + Z - 5);
|
|
|
|
MoveToPosition(Vector3f((float) (m_CropsPos.x + 0.5), (float) m_CropsPos.y, (float) (m_CropsPos.z + 0.5)));
|
|
|
|
return;
|
2014-07-17 16:15:34 -04:00
|
|
|
} // for Y loop.
|
|
|
|
} // Repeat the procces 5 times.
|
2014-01-27 08:40:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-27 09:44:55 -05:00
|
|
|
|
2014-01-28 10:26:44 -05:00
|
|
|
void cVillager::HandleFarmerTryHarvestCrops()
|
2014-01-27 15:34:22 -05:00
|
|
|
{
|
2014-01-27 15:39:00 -05:00
|
|
|
// Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
|
2014-01-27 15:34:22 -05:00
|
|
|
if (!m_bMovingToDestination && (GetPosition() - m_CropsPos).Length() < 2)
|
|
|
|
{
|
2014-01-27 15:39:00 -05:00
|
|
|
// Check if the blocks didn't change while the villager was walking to the coordinates.
|
2014-01-27 15:34:22 -05:00
|
|
|
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)
|
|
|
|
{
|
2014-03-02 14:25:05 -05:00
|
|
|
cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock);
|
2014-02-02 09:49:37 -05: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);
|
2014-01-27 15:34:22 -05:00
|
|
|
m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_AIR, 0);
|
|
|
|
m_ActionCountDown = 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-28 10:26:44 -05:00
|
|
|
void cVillager::HandleFarmerPlaceCrops()
|
2014-01-27 15:34:22 -05:00
|
|
|
{
|
2014-01-27 15:39:00 -05:00
|
|
|
// Check if there is still farmland at the spot where the crops were.
|
2014-01-27 15:34:22 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-27 09:44:55 -05:00
|
|
|
bool cVillager::IsBlockFarmable(BLOCKTYPE a_BlockType)
|
|
|
|
{
|
|
|
|
switch (a_BlockType)
|
|
|
|
{
|
|
|
|
case E_BLOCK_CROPS:
|
|
|
|
case E_BLOCK_POTATOES:
|
|
|
|
case E_BLOCK_CARROTS:
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|