aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/DispenserTile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/DispenserTile.cpp')
-rw-r--r--Minecraft.World/DispenserTile.cpp448
1 files changed, 64 insertions, 384 deletions
diff --git a/Minecraft.World/DispenserTile.cpp b/Minecraft.World/DispenserTile.cpp
index 286737c9..8758b3c5 100644
--- a/Minecraft.World/DispenserTile.cpp
+++ b/Minecraft.World/DispenserTile.cpp
@@ -3,6 +3,7 @@
#include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.entity.projectile.h"
#include "net.minecraft.world.item.h"
+#include "net.minecraft.world.inventory.h"
#include "net.minecraft.world.level.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.level.tile.entity.h"
@@ -11,7 +12,9 @@
#include "net.minecraft.h"
#include "Mob.h"
-DispenserTile::DispenserTile(int id) : EntityTile(id, Material::stone)
+BehaviorRegistry DispenserTile::REGISTRY = BehaviorRegistry(new DefaultDispenseItemBehavior());
+
+DispenserTile::DispenserTile(int id) : BaseEntityTile(id, Material::stone)
{
random = new Random();
@@ -20,19 +23,14 @@ DispenserTile::DispenserTile(int id) : EntityTile(id, Material::stone)
iconFrontVertical = NULL;
}
-int DispenserTile::getTickDelay()
+int DispenserTile::getTickDelay(Level *level)
{
return 4;
}
-int DispenserTile::getResource(int data, Random *random, int playerBonusLevel)
-{
- return Tile::dispenser_Id;
-}
-
void DispenserTile::onPlace(Level *level, int x, int y, int z)
{
- EntityTile::onPlace(level, x, y, z);
+ BaseEntityTile::onPlace(level, x, y, z);
recalcLockDir(level, x, y, z);
}
@@ -53,7 +51,7 @@ void DispenserTile::recalcLockDir(Level *level, int x, int y, int z)
if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2;
if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5;
if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4;
- level->setData(x, y, z, lockDir);
+ level->setData(x, y, z, lockDir, Tile::UPDATE_CLIENTS);
}
Icon *DispenserTile::getTexture(int face, int data)
@@ -113,80 +111,58 @@ bool DispenserTile::use(Level *level, int x, int y, int z, shared_ptr<Player> pl
return true;
}
-void DispenserTile::fireArrow(Level *level, int x, int y, int z, Random *random)
+void DispenserTile::dispenseFrom(Level *level, int x, int y, int z)
{
- const int lockDir = level->getData(x, y, z);
- //const float power = 1.1f;
- const int accuracy = 6;
- //bool bLaunched=true;
+ BlockSourceImpl source(level, x, y, z);
+ shared_ptr<DispenserTileEntity> trap = dynamic_pointer_cast<DispenserTileEntity>( source.getEntity() );
+ if (trap == NULL) return;
- int xd = 0, zd = 0;
- if (lockDir == Facing::SOUTH)
+ int slot = trap->getRandomSlot();
+ if (slot < 0)
{
- zd = 1;
- }
- else if (lockDir == Facing::NORTH)
- {
- zd = -1;
- }
- else if (lockDir == Facing::EAST)
- {
- xd = 1;
+ level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
}
else
{
- xd = -1;
- }
-
- shared_ptr<DispenserTileEntity> trap = dynamic_pointer_cast<DispenserTileEntity>( level->getTileEntity(x, y, z) );
- if(trap != NULL)
- {
- int slot=trap->getRandomSlot();
+ shared_ptr<ItemInstance> item = trap->getItem(slot);
+ DispenseItemBehavior *behavior = getDispenseMethod(item);
- if (slot < 0)
+ if (behavior != DispenseItemBehavior::NOOP)
{
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
- }
- else
- {
- double xp = x + xd * 0.6 + 0.5;
- double yp = y + 0.5;
- double zp = z + zd * 0.6 + 0.5;
- shared_ptr<ItemInstance> item=trap->getItem(slot);
- int result = dispenseItem(trap, level, item, random, x, y, z, xd, zd, xp, yp, zp);
- if (result == REMOVE_ITEM)
- {
- trap->removeItem(slot, 1);
- }
- else if (result == DISPENSE_ITEM)
- {
- item = trap->removeItem(slot, 1);
- throwItem(level, item, random, accuracy, xd, zd, xp, yp, zp);
- level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0);
- }
+ shared_ptr<ItemInstance> leftOver = behavior->dispense(&source, item);
- level->levelEvent(LevelEvent::PARTICLES_SHOOT, x, y, z, (xd + 1) + (zd + 1) * 3);
+ trap->setItem(slot, leftOver->count == 0 ? nullptr : leftOver);
}
}
}
+DispenseItemBehavior *DispenserTile::getDispenseMethod(shared_ptr<ItemInstance> item)
+{
+ return REGISTRY.get(item->getItem());
+}
+
void DispenserTile::neighborChanged(Level *level, int x, int y, int z, int type)
{
- if (type > 0 && Tile::tiles[type]->isSignalSource())
+ bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z);
+ int data = level->getData(x, y, z);
+ bool isTriggered = (data & TRIGGER_BIT) != 0;
+
+ if (signal && !isTriggered)
{
- bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z);
- if (signal)
- {
- level->addToTickNextTick(x, y, z, this->id, getTickDelay());
- }
+ level->addToTickNextTick(x, y, z, id, getTickDelay(level));
+ level->setData(x, y, z, data | TRIGGER_BIT, UPDATE_NONE);
+ }
+ else if (!signal && isTriggered)
+ {
+ level->setData(x, y, z, data & ~TRIGGER_BIT, UPDATE_NONE);
}
}
void DispenserTile::tick(Level *level, int x, int y, int z, Random *random)
{
- if (!level->isClientSide && ( level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z)))
+ if (!level->isClientSide) // && (level.hasNeighborSignal(x, y, z) || level.hasNeighborSignal(x, y + 1, z)))
{
- fireArrow(level, x, y, z, random);
+ dispenseFrom(level, x, y, z);
}
}
@@ -195,14 +171,16 @@ shared_ptr<TileEntity> DispenserTile::newTileEntity(Level *level)
return shared_ptr<DispenserTileEntity>( new DispenserTileEntity() );
}
-void DispenserTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr<Mob> by)
+void DispenserTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr<LivingEntity> by, shared_ptr<ItemInstance> itemInstance)
{
- int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3;
+ int dir = PistonBaseTile::getNewFacing(level, x, y, z, by);
- if (dir == 0) level->setData(x, y, z, Facing::NORTH);
- if (dir == 1) level->setData(x, y, z, Facing::EAST);
- if (dir == 2) level->setData(x, y, z, Facing::SOUTH);
- if (dir == 3) level->setData(x, y, z, Facing::WEST);
+ level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS);
+
+ if (itemInstance->hasCustomHoverName())
+ {
+ dynamic_pointer_cast<DispenserTileEntity>( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName());
+ }
}
void DispenserTile::onRemove(Level *level, int x, int y, int z, int id, int data)
@@ -243,331 +221,33 @@ void DispenserTile::onRemove(Level *level, int x, int y, int z, int id, int data
container->setItem(i,nullptr);
}
}
+ level->updateNeighbourForOutputSignal(x, y, z, id);
}
- EntityTile::onRemove(level, x, y, z, id, data);
+ BaseEntityTile::onRemove(level, x, y, z, id, data);
}
-void DispenserTile::throwItem(Level *level, shared_ptr<ItemInstance> item, Random *random, int accuracy, int xd, int zd, double xp, double yp, double zp)
+Position *DispenserTile::getDispensePosition(BlockSource *source)
{
- shared_ptr<ItemEntity> itemEntity = shared_ptr<ItemEntity>(new ItemEntity(level, xp, yp - 0.3, zp, item));
+ FacingEnum *facing = getFacing(source->getData());
- double pow = random->nextDouble() * 0.1 + 0.2;
- itemEntity->xd = xd * pow;
- itemEntity->yd = .2f;
- itemEntity->zd = zd * pow;
+ double originX = source->getX() + 0.7 * facing->getStepX();
+ double originY = source->getY() + 0.7 * facing->getStepY();
+ double originZ = source->getZ() + 0.7 * facing->getStepZ();
- itemEntity->xd += (random->nextGaussian()) * 0.0075f * accuracy;
- itemEntity->yd += (random->nextGaussian()) * 0.0075f * accuracy;
- itemEntity->zd += (random->nextGaussian()) * 0.0075f * accuracy;
-
- level->addEntity(itemEntity);
+ return new PositionImpl(originX, originY, originZ);
}
-int DispenserTile::dispenseItem(shared_ptr<DispenserTileEntity> trap, Level *level, shared_ptr<ItemInstance> item, Random *random, int x, int y, int z, int xd, int zd, double xp, double yp, double zp)
+FacingEnum *DispenserTile::getFacing(int data)
{
- float power = 1.1f;
- int accuracy = 6;
-
- // 4J-PB - moved to a switch
- switch(item->id)
- {
- case Item::arrow_Id:
- {
- int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false);
- if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit
- {
- shared_ptr<Arrow> arrow = shared_ptr<Arrow>( new Arrow(level, xp, yp, zp) );
- arrow->shoot(xd, .1f, zd, power, (float) accuracy);
- arrow->pickup = Arrow::PICKUP_ALLOWED;
- level->addEntity(arrow);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::egg_Id:
- {
- int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false);
- if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit
- {
- shared_ptr<ThrownEgg> egg = shared_ptr<ThrownEgg>( new ThrownEgg(level, xp, yp, zp) );
- egg->shoot(xd, .1f, zd, power, (float) accuracy);
- level->addEntity(egg);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::snowBall_Id:
- {
- int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false);
- if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit
- {
- shared_ptr<Snowball> snowball = shared_ptr<Snowball>( new Snowball(level, xp, yp, zp) );
- snowball->shoot(xd, .1f, zd, power, (float) accuracy);
- level->addEntity(snowball);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::potion_Id:
- {
- int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false);
- if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit
- {
- if(PotionItem::isThrowable(item->getAuxValue()))
- {
- shared_ptr<ThrownPotion> potion = shared_ptr<ThrownPotion>(new ThrownPotion(level, xp, yp, zp, item->getAuxValue()));
- potion->shoot(xd, .1f, zd, power * 1.25f, accuracy * .5f);
- level->addEntity(potion);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- }
- else
- {
- shared_ptr<ItemEntity> itemEntity = shared_ptr<ItemEntity>( new ItemEntity(level, xp, yp - 0.3, zp, item) );
-
- double pow = random->nextDouble() * 0.1 + 0.2;
- itemEntity->xd = xd * pow;
- itemEntity->yd = .2f;
- itemEntity->zd = zd * pow;
-
- itemEntity->xd += (random->nextGaussian()) * 0.0075f * accuracy;
- itemEntity->yd += (random->nextGaussian()) * 0.0075f * accuracy;
- itemEntity->zd += (random->nextGaussian()) * 0.0075f * accuracy;
-
- level->addEntity(itemEntity);
- level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0);
- }
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::expBottle_Id:
- {
- int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false);
- if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit
- {
- shared_ptr<ThrownExpBottle> expBottle = shared_ptr<ThrownExpBottle>( new ThrownExpBottle(level, xp, yp, zp) );
- expBottle->shoot(xd, .1f, zd, power * 1.25f, accuracy * .5f);
- level->addEntity(expBottle);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::fireball_Id: // TU9
- {
- int currentFireballs = level->countInstanceOf(eTYPE_SMALL_FIREBALL,true);
- if(currentFireballs < Level::MAX_DISPENSABLE_FIREBALLS) // 4J - added limit
- {
- shared_ptr<SmallFireball> fireball = shared_ptr<SmallFireball>( new SmallFireball(level, xp + xd * .3, yp, zp + zd * .3, xd + random->nextGaussian() * .05, random->nextGaussian() * .05, zd + random->nextGaussian() * .05));
- level->addEntity(fireball);
- level->levelEvent(LevelEvent::SOUND_BLAZE_FIREBALL, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::monsterPlacer_Id:
- {
- int iResult=0;
- //MonsterPlacerItem *spawnEgg = (MonsterPlacerItem *)item->getItem();
- shared_ptr<Entity> newEntity = MonsterPlacerItem::canSpawn(item->getAuxValue(), level,&iResult);
-
- shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(newEntity);
- if (mob != NULL)
- {
- // 4J-PB - Changed the line below slightly since mobs were sticking to the dispenser rather than dropping down when fired
- mob->moveTo(xp + xd * 0.4, yp - 0.3, zp + zd * 0.4, level->random->nextFloat() * 360, 0);
- mob->finalizeMobSpawn();
- level->addEntity(mob);
- level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- // some negative sound effect?
- level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0);
-
- // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs
- return LEAVE_ITEM;
- }
- }
- break;
- case Item::bucket_lava_Id:
- case Item::bucket_water_Id:
- {
- BucketItem *pBucket = (BucketItem *) item->getItem();
-
- if (pBucket->emptyBucket(level, x, y, z, x + xd, y, z + zd))
- {
- item->id = Item::bucket_empty_Id;
- item->count = 1;
- return LEAVE_ITEM;
- }
- return DISPENSE_ITEM;
- }
- break;
- case Item::bucket_empty_Id:
- {
- int xt = x + xd;
- int zt = z + zd;
- Material *pMaterial=level->getMaterial(xt, y, zt);
- int data = level->getData(xt, y, zt);
-
- if (pMaterial == Material::water && data == 0)
- {
- level->setTile(xt, y, zt, 0);
-
- if (--item->count == 0)
- {
- item->id = Item::bucket_water_Id;
- item->count = 1;
- }
- else if (trap->addItem(shared_ptr<ItemInstance>(new ItemInstance(Item::bucket_water))) < 0)
- {
- throwItem(level, shared_ptr<ItemInstance>(new ItemInstance(Item::bucket_water)), random, 6, xd, zd, xp, yp, zp);
- }
-
- return LEAVE_ITEM;
- }
- else if (pMaterial == Material::lava && data == 0)
- {
- level->setTile(xt, y, zt, 0);
-
- if (--item->count == 0)
- {
- item->id = Item::bucket_lava_Id;
- item->count = 1;
- }
- else if (trap->addItem(shared_ptr<ItemInstance>(new ItemInstance(Item::bucket_lava))) < 0)
- {
- throwItem(level, shared_ptr<ItemInstance>(new ItemInstance(Item::bucket_lava)), random, 6, xd, zd, xp, yp, zp);
- }
-
- return LEAVE_ITEM;
- }
- return DISPENSE_ITEM;
- }
-
- break;
- // TU12
- case Item::minecart_Id:
- case Item::minecart_chest_Id:
- case Item::minecart_furnace_Id:
- {
- xp = x + (xd < 0 ? xd * 0.8 : xd * 1.8f) + Mth::abs(zd) * 0.5f;
- zp = z + (zd < 0 ? zd * 0.8 : zd * 1.8f) + Mth::abs(xd) * 0.5f;
-
- if (RailTile::isRail(level, x + xd, y, z + zd))
- {
- yp = y + 0.5f;
- }
- else if (level->isEmptyTile(x + xd, y, z + zd) && RailTile::isRail(level, x + xd, y - 1, z + zd))
- {
- yp = y - 0.5f;
- }
- else
- {
- return DISPENSE_ITEM;
- }
-
- if( level->countInstanceOf(eTYPE_MINECART, true) < Level::MAX_CONSOLE_MINECARTS ) // 4J - added limit
- {
- shared_ptr<Minecart> minecart = shared_ptr<Minecart>(new Minecart(level, xp, yp, zp, ((MinecartItem *) item->getItem())->type));
- level->addEntity(minecart);
- level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0);
-
- return REMOVE_ITEM;
- }
- else
- {
- return DISPENSE_ITEM;
- }
- }
- break;
-
- case Item::boat_Id:
- {
- bool bLaunchBoat=false;
-
- xp = x + (xd < 0 ? xd * 0.8 : xd * 1.8f) + Mth::abs(zd) * 0.5f;
- zp = z + (zd < 0 ? zd * 0.8 : zd * 1.8f) + Mth::abs(xd) * 0.5f;
-
- if (level->getMaterial(x + xd, y, z + zd) == Material::water)
- {
- bLaunchBoat=true;
- yp = y + 1.0f;
- }
- else if (level->isEmptyTile(x + xd, y, z + zd) && level->getMaterial(x + xd, y - 1, z + zd) == Material::water)
- {
- bLaunchBoat=true;
- yp = y;
- }
-
- // check the limit on boats
- if( bLaunchBoat && level->countInstanceOf(eTYPE_BOAT, true) < Level::MAX_XBOX_BOATS ) // 4J - added limit
- {
- shared_ptr<Boat> boat = shared_ptr<Boat>(new Boat(level, xp, yp, zp));
- level->addEntity(boat);
- level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0);
- return REMOVE_ITEM;
- }
- else
- {
- return DISPENSE_ITEM;
- }
- }
- break;
- }
+ return FacingEnum::fromData(data & FACING_MASK);
+}
- return DISPENSE_ITEM;
+bool DispenserTile::hasAnalogOutputSignal()
+{
+ return true;
}
+
+int DispenserTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir)
+{
+ return AbstractContainerMenu::getRedstoneSignalFromContainer(dynamic_pointer_cast<Container>( level->getTileEntity(x, y, z)) );
+} \ No newline at end of file