1
0

Dispensers can dispense items and liquids now

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1105 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
luksor111@gmail.com 2012-12-26 17:16:33 +00:00
parent 17a2c1b388
commit 575abe8691
10 changed files with 320 additions and 3 deletions

View File

@ -442,7 +442,15 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
m_IsDirty = ((cFurnaceEntity *)(*itr))->Tick( a_Dt ) | m_IsDirty;
}
}
// Tick block entities (dispensers)
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{
if ((*itr)->GetBlockType() == E_BLOCK_DISPENSER)
{
m_IsDirty = ((cDispenserEntity *)(*itr))->Tick( a_Dt ) | m_IsDirty;
}
}
ApplyWeatherToTop(a_TickRandom);
}
@ -1588,6 +1596,28 @@ bool cChunk::ForEachChest(cChestCallback & a_Callback)
bool cChunk::ForEachDispenser(cDispenserCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
{
++itr2;
if ((*itr)->GetBlockType() != E_BLOCK_DISPENSER)
{
continue;
}
if (a_Callback.Item((cDispenserEntity *)*itr))
{
return false;
}
} // for itr - m_BlockEntitites[]
return true;
}
bool cChunk::ForEachFurnace(cFurnaceCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
@ -1650,6 +1680,38 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
{
++itr2;
if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
{
continue;
}
if ((*itr)->GetBlockType() != E_BLOCK_DISPENSER)
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false;
}
// The correct block entity is here
if (a_Callback.Item((cDispenserEntity *)*itr))
{
return false;
}
return true;
} // for itr - m_BlockEntitites[]
// Not found:
return false;
}
bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS

View File

@ -168,12 +168,18 @@ public:
/// Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true
bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible
/// Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true
bool ForEachDispenser(cDispenserCallback & a_Callback); // Lua-accessible
/// Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true
bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords, true if found
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords, true if found
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible

View File

@ -1354,6 +1354,21 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback &
bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return false;
}
return Chunk->ForEachDispenser(a_Callback);
}
bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback)
{
cCSLock Lock(m_CSLayers);
@ -1387,6 +1402,24 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa
bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return false;
}
return Chunk->DoWithDispenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{
int ChunkX, ChunkZ;

View File

@ -184,12 +184,18 @@ public:
/// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible
/// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); // Lua-accessible
/// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Lua-accessible
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords, true if found
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords, true if found
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible

View File

@ -11,15 +11,30 @@
#include "Server.h"
#include "Pickup.h"
#include "Root.h"
#include "Simulator/FluidSimulator.h"
#include <json/json.h>
#define AddDispenserDir(x, y, z, dir) \
switch (dir) \
{ \
case 2: (z) --; break; \
case 3: (z) ++; break; \
case 4: (x) --; break; \
case 5: (x) ++; break; \
}
cDispenserEntity::cDispenserEntity(int a_X, int a_Y, int a_Z, cWorld * a_World)
: cBlockEntity( E_BLOCK_DISPENSER, a_X, a_Y, a_Z, a_World )
, m_Items( new cItem[9] )
, m_CanDispense( 0 )
{
SetBlockEntity(this); // cBlockEntityWindowOwner
}
@ -51,7 +66,7 @@ void cDispenserEntity::Destroy()
{
// Drop items
cItems Pickups;
for( int i = 0; i < 3; i++)
for( int i = 0; i < 9; i++)
{
if( !m_Items[i].IsEmpty() )
{
@ -66,6 +81,120 @@ void cDispenserEntity::Destroy()
void cDispenserEntity::Dispense()
{
int Disp_X = m_PosX;
int Disp_Y = m_PosY;
int Disp_Z = m_PosZ;
NIBBLETYPE Meta = m_World->GetBlockMeta( m_PosX, m_PosY, m_PosZ );
AddDispenserDir( Disp_X, Disp_Y, Disp_Z, Meta );
char OccupiedSlots[9];
char SlotsCnt = 0;
for( int i = 0; i < 9; i++)
{
if( !m_Items[i].IsEmpty() )
{
OccupiedSlots[SlotsCnt] = i;
SlotsCnt++;
}
}
if(SlotsCnt > 0)
{
MTRand r1;
cItem Drop = m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]];
switch( m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemType )
{
case E_ITEM_BUCKET:
{
BLOCKTYPE DispBlock = m_World->GetBlock( Disp_X, Disp_Y, Disp_Z );
if( DispBlock == E_BLOCK_STATIONARY_WATER )
{
m_World->SetBlock( Disp_X, Disp_Y, Disp_Z, E_BLOCK_AIR, 0 );
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemType = E_ITEM_WATER_BUCKET;
}
else if( DispBlock == E_BLOCK_STATIONARY_LAVA )
{
m_World->SetBlock( Disp_X, Disp_Y, Disp_Z, E_BLOCK_AIR, 0 );
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemType = E_ITEM_LAVA_BUCKET;
}
else
{
cItems Pickups;
Pickups.push_back(cItem(Drop.m_ItemType, 1, Drop.m_ItemHealth));
m_World->SpawnItemPickups(Pickups, Disp_X, Disp_Y, Disp_Z);
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemCount--;
}
break;
}
case E_ITEM_WATER_BUCKET:
{
BLOCKTYPE DispBlock = m_World->GetBlock( Disp_X, Disp_Y, Disp_Z );
if( DispBlock == E_BLOCK_AIR || IsBlockLiquid(DispBlock) || cFluidSimulator::CanWashAway(DispBlock) )
{
m_World->SetBlock( Disp_X, Disp_Y, Disp_Z, E_BLOCK_STATIONARY_WATER, 0 );
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemType = E_ITEM_BUCKET;
}
else
{
cItems Pickups;
Pickups.push_back(cItem(Drop.m_ItemType, 1, Drop.m_ItemHealth));
m_World->SpawnItemPickups(Pickups, Disp_X, Disp_Y, Disp_Z);
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemCount--;
}
break;
}
case E_ITEM_LAVA_BUCKET:
{
BLOCKTYPE DispBlock = m_World->GetBlock( Disp_X, Disp_Y, Disp_Z );
if( DispBlock == E_BLOCK_AIR || IsBlockLiquid(DispBlock) || cFluidSimulator::CanWashAway(DispBlock) )
{
m_World->SetBlock( Disp_X, Disp_Y, Disp_Z, E_BLOCK_STATIONARY_LAVA, 0 );
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemType = E_ITEM_BUCKET;
}
else
{
cItems Pickups;
Pickups.push_back(cItem(Drop.m_ItemType, 1, Drop.m_ItemHealth));
m_World->SpawnItemPickups(Pickups, Disp_X, Disp_Y, Disp_Z);
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemCount--;
}
break;
}
default:
{
cItems Pickups;
Pickups.push_back(cItem(Drop.m_ItemType, 1, Drop.m_ItemHealth));
m_World->SpawnItemPickups(Pickups, Disp_X, Disp_Y, Disp_Z);
m_Items[OccupiedSlots[r1.randInt() % SlotsCnt]].m_ItemCount--;
break;
}
}
char SmokeDir;
switch( Meta )
{
case 2: SmokeDir = 1; break;
case 3: SmokeDir = 7; break;
case 4: SmokeDir = 3; break;
case 5: SmokeDir = 5; break;
}
m_World->BroadcastSoundParticleEffect(2000, m_PosX * 8, m_PosY * 8, m_PosZ * 8, SmokeDir);
m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.0f);
cWindow * Window = GetWindow();
if ( Window != NULL )
{
Window->BroadcastWholeWindow();
}
}
else
{
m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.2f);
}
}
void cDispenserEntity::UsedBy(cPlayer * a_Player)
{
if (GetWindow() == NULL)
@ -86,9 +215,23 @@ void cDispenserEntity::UsedBy(cPlayer * a_Player)
void cDispenserEntity::Activate()
{
m_CanDispense = 1;
}
bool cDispenserEntity::Tick( float a_Dt )
{
return true;
if(m_CanDispense)
{
m_CanDispense = 0;
Dispense();
}
return false;
}

View File

@ -45,9 +45,14 @@ public:
const cItem * GetSlot(int i) const { return &(m_Items[i]); }
void SetSlot(int a_Slot, const cItem & a_Item);
void Activate();
private:
cItem * m_Items;
bool m_CanDispense;
void Dispense();
};

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "RedstoneSimulator.h"
#include "../DispenserEntity.h"
#include "../Piston.h"
#include "../World.h"
#include "../BlockID.h"
@ -387,6 +388,36 @@ void cRedstoneSimulator::HandleChange( const Vector3i & a_BlockPos )
}
} // switch (BlockType)
} // while (m_RefreshPistons[])
while (!m_RefreshDispensers.empty())
{
Vector3i pos = m_RefreshDispensers.back();
m_RefreshDispensers.pop_back();
BLOCKTYPE BlockType = m_World->GetBlock(pos);
if (BlockType == E_BLOCK_DISPENSER)
{
if (IsPowered(pos))
{
class cActivateDispenser :
public cDispenserCallback
{
public:
cActivateDispenser()
{
}
virtual bool Item(cDispenserEntity * a_Dispenser) override
{
a_Dispenser->Activate();
return false;
}
} ;
cActivateDispenser DispAct;
m_World->DoWithDispenserAt(pos.x, pos.y, pos.z, DispAct);
}
}
}
}
@ -416,6 +447,12 @@ bool cRedstoneSimulator::PowerBlock(const Vector3i & a_BlockPos, const Vector3i
m_RefreshPistons.push_back(a_BlockPos);
break;
}
case E_BLOCK_DISPENSER:
{
m_RefreshDispensers.push_back(a_BlockPos);
break;
}
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:

View File

@ -71,6 +71,7 @@ private:
BlockList m_BlocksBuffer;
BlockList m_RefreshPistons;
BlockList m_RefreshDispensers;
BlockList m_RefreshTorchesAround;

View File

@ -736,6 +736,15 @@ bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_
bool cWorld::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback)
{
return m_ChunkMap->ForEachDispenserInChunk(a_ChunkX, a_ChunkZ, a_Callback);
}
bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback)
{
return m_ChunkMap->ForEachFurnaceInChunk(a_ChunkX, a_ChunkZ, a_Callback);
@ -754,6 +763,15 @@ bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
bool cWorld::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{
return m_ChunkMap->DoWithDispenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cWorld::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{
return m_ChunkMap->DoWithFurnaceAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);

View File

@ -318,12 +318,18 @@ public:
/// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords, true if found
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords, true if found
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp