TU19: add Minecraft.World/Core

This commit is contained in:
Tropical 2026-03-21 15:54:53 -05:00
parent 9b6046cb83
commit 7d05b36f85
21 changed files with 1071 additions and 0 deletions

View file

@ -0,0 +1,45 @@
#include "../Platform/stdafx.h"
#include "AbstractProjectileDispenseBehavior.h"
#include "../Blocks/DispenserTile.h"
#include "../Entities/Projectile.h"
#include "../Level/Level.h"
#include "../Level/Events/LevelEvent.h"
#include "../Items/ItemInstance.h"
std::shared_ptr<ItemInstance> AbstractProjectileDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
Level* world = source->getWorld();
if (world->countInstanceOf(eTYPE_PROJECTILE, false) >=
Level::MAX_DISPENSABLE_PROJECTILES) {
return DefaultDispenseItemBehavior::execute(source, dispensed, outcome);
}
Position* position = DispenserTile::getDispensePosition(source);
FacingEnum* facing = DispenserTile::getFacing(source->getData());
std::shared_ptr<Projectile> projectile = getProjectile(world, position);
delete position;
projectile->shoot(facing->getStepX(), facing->getStepY() + .1f,
facing->getStepZ(), getPower(), getUncertainty());
world->addEntity(std::dynamic_pointer_cast<Entity>(projectile));
dispensed->remove(1);
return dispensed;
}
void AbstractProjectileDispenseBehavior::playSound(BlockSource* source,
eOUTCOME outcome) {
if (outcome != LEFT_ITEM) {
source->getWorld()->levelEvent(LevelEvent::SOUND_LAUNCH,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
}
}
float AbstractProjectileDispenseBehavior::getUncertainty() { return 6.0f; }
float AbstractProjectileDispenseBehavior::getPower() { return 1.1f; }

View file

@ -0,0 +1,19 @@
#pragma once
#include "DefaultDispenseItemBehavior.h"
class Projectile;
class Position;
class AbstractProjectileDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
virtual float getUncertainty();
virtual float getPower();
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position) = 0;
};

View file

@ -0,0 +1,3 @@
#pragma once
class Behavior {};

View file

@ -0,0 +1,25 @@
#include "../Platform/stdafx.h"
#include "BehaviorRegistry.h"
BehaviorRegistry::BehaviorRegistry(DispenseItemBehavior* defaultValue) {
defaultBehavior = defaultValue;
}
BehaviorRegistry::~BehaviorRegistry() {
for (AUTO_VAR(it, storage.begin()); it != storage.end(); ++it) {
delete it->second;
}
delete defaultBehavior;
}
DispenseItemBehavior* BehaviorRegistry::get(Item* key) {
AUTO_VAR(it, storage.find(key));
return (it == storage.end()) ? defaultBehavior : it->second;
}
void BehaviorRegistry::add(Item* key, DispenseItemBehavior* value) {
storage.insert(std::make_pair(key, value));
}

View file

@ -0,0 +1,16 @@
#pragma once
class DispenseItemBehavior;
class BehaviorRegistry {
private:
std::unordered_map<Item*, DispenseItemBehavior*> storage;
DispenseItemBehavior* defaultBehavior;
public:
BehaviorRegistry(DispenseItemBehavior* defaultValue);
~BehaviorRegistry();
DispenseItemBehavior* get(Item* key);
void add(Item* key, DispenseItemBehavior* value);
};

View file

@ -0,0 +1,35 @@
#pragma once
#include "LocatableSource.h"
class Tile;
class Material;
class TileEntity;
class BlockSource : public LocatableSource {
public:
/**
* @return The X coordinate for the middle of the block
*/
virtual double getX() = 0;
/**
* @return The Y coordinate for the middle of the block
*/
virtual double getY() = 0;
/**
* @return The Z coordinate for the middle of the block
*/
virtual double getZ() = 0;
virtual int getBlockX() = 0;
virtual int getBlockY() = 0;
virtual int getBlockZ() = 0;
virtual Tile* getType() = 0;
virtual int getData() = 0;
virtual Material* getMaterial() = 0;
virtual std::shared_ptr<TileEntity> getEntity() = 0;
};

View file

@ -0,0 +1,38 @@
#include "../Platform/stdafx.h"
#include "BlockSourceImpl.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.world.level.tile.entity.h"
BlockSourceImpl::BlockSourceImpl(Level* world, int x, int y, int z) {
this->world = world;
this->x = x;
this->y = y;
this->z = z;
}
Level* BlockSourceImpl::getWorld() { return world; }
double BlockSourceImpl::getX() { return x + 0.5; }
double BlockSourceImpl::getY() { return y + 0.5; }
double BlockSourceImpl::getZ() { return z + 0.5; }
int BlockSourceImpl::getBlockX() { return x; }
int BlockSourceImpl::getBlockY() { return y; }
int BlockSourceImpl::getBlockZ() { return z; }
Tile* BlockSourceImpl::getType() {
return Tile::tiles[world->getTile(x, y, z)];
}
int BlockSourceImpl::getData() { return world->getData(x, y, z); }
Material* BlockSourceImpl::getMaterial() { return world->getMaterial(x, y, z); }
std::shared_ptr<TileEntity> BlockSourceImpl::getEntity() {
return world->getTileEntity(x, y, z);
}

View file

@ -0,0 +1,28 @@
#pragma once
#include "BlockSource.h"
class Level;
class BlockSourceImpl : public BlockSource {
private:
Level* world;
int x;
int y;
int z;
public:
BlockSourceImpl(Level* world, int x, int y, int z);
Level* getWorld();
double getX();
double getY();
double getZ();
int getBlockX();
int getBlockY();
int getBlockZ();
Tile* getType();
int getData();
Material* getMaterial();
std::shared_ptr<TileEntity> getEntity();
};

View file

@ -0,0 +1,87 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.h"
#include "../Headers/net.minecraft.core.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.entity.item.h"
#include "DefaultDispenseItemBehavior.h"
std::shared_ptr<ItemInstance> DefaultDispenseItemBehavior::dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed) {
eOUTCOME outcome = DISPENCED_ITEM;
std::shared_ptr<ItemInstance> result = execute(source, dispensed, outcome);
playSound(source, outcome);
playAnimation(source, DispenserTile::getFacing(source->getData()), outcome);
return result;
}
std::shared_ptr<ItemInstance> DefaultDispenseItemBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Position* position = DispenserTile::getDispensePosition(source);
std::shared_ptr<ItemInstance> itemInstance = dispensed->remove(1);
spawnItem(source->getWorld(), itemInstance, 6, facing, position);
delete position;
outcome = DISPENCED_ITEM;
return dispensed;
}
void DefaultDispenseItemBehavior::spawnItem(Level* world,
std::shared_ptr<ItemInstance> item,
int accuracy, FacingEnum* facing,
Position* position) {
double spawnX = position->getX();
double spawnY = position->getY();
double spawnZ = position->getZ();
std::shared_ptr<ItemEntity> itemEntity = std::shared_ptr<ItemEntity>(
new ItemEntity(world, spawnX, spawnY - 0.3, spawnZ, item));
double pow = world->random->nextDouble() * 0.1 + 0.2;
itemEntity->xd = facing->getStepX() * pow;
itemEntity->yd = .2f;
itemEntity->zd = facing->getStepZ() * pow;
itemEntity->xd += world->random->nextGaussian() * 0.0075f * accuracy;
itemEntity->yd += world->random->nextGaussian() * 0.0075f * accuracy;
itemEntity->zd += world->random->nextGaussian() * 0.0075f * accuracy;
world->addEntity(itemEntity);
}
void DefaultDispenseItemBehavior::playSound(BlockSource* source,
eOUTCOME outcome) {
if (outcome != LEFT_ITEM) {
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
} else {
// some negative sound effect?
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
}
}
void DefaultDispenseItemBehavior::playAnimation(BlockSource* source,
FacingEnum* facing,
eOUTCOME outcome) {
if (outcome != LEFT_ITEM) {
source->getWorld()->levelEvent(LevelEvent::PARTICLES_SHOOT,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(),
getLevelEventDataFrom(facing));
} else {
}
}
int DefaultDispenseItemBehavior::getLevelEventDataFrom(FacingEnum* facing) {
return facing->getStepX() + 1 + (facing->getStepZ() + 1) * 3;
}

View file

@ -0,0 +1,44 @@
#pragma once
#include "DispenseItemBehavior.h"
class FacingEnum;
class Position;
class DefaultDispenseItemBehavior : public DispenseItemBehavior {
protected:
enum eOUTCOME {
// Item has special behaviour that was executed successfully.
ACTIVATED_ITEM = 0,
// Item was dispenced onto the ground as a pickup.
DISPENCED_ITEM = 1,
// Execution failed, the item was left unaffected.
LEFT_ITEM = 2,
};
public:
DefaultDispenseItemBehavior() {};
virtual ~DefaultDispenseItemBehavior() {};
virtual std::shared_ptr<ItemInstance> dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed);
protected:
// 4J-JEV: Added value used to play FAILED sound effect upon reaching spawn
// limits.
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
public:
static void spawnItem(Level* world, std::shared_ptr<ItemInstance> item,
int accuracy, FacingEnum* facing, Position* position);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
virtual void playAnimation(BlockSource* source, FacingEnum* facing,
eOUTCOME outcome);
private:
virtual int getLevelEventDataFrom(FacingEnum* facing);
};

View file

@ -0,0 +1,11 @@
#include "../Platform/stdafx.h"
#include "DispenseItemBehavior.h"
DispenseItemBehavior* DispenseItemBehavior::NOOP =
new NoOpDispenseItemBehavior();
std::shared_ptr<ItemInstance> NoOpDispenseItemBehavior::dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed) {
return dispensed;
}

View file

@ -0,0 +1,29 @@
#pragma once
#include "Behavior.h"
class ItemInstance;
class BlockSource;
class DispenseItemBehavior : public Behavior {
public:
/**
* The 'do nothing' behavior.
*/
static DispenseItemBehavior* NOOP;
/**
*
* @param source The source of this call (the dispenser that calls it)
* @param dispensed The ItemInstance which is being dispensed
* @return The ItemInstance that should is 'left over'
*/
virtual std::shared_ptr<ItemInstance> dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed) = 0;
};
class NoOpDispenseItemBehavior : public DispenseItemBehavior {
public:
std::shared_ptr<ItemInstance> dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed);
};

View file

@ -0,0 +1,34 @@
#include "../Platform/stdafx.h"
#include "FacingEnum.h"
FacingEnum* FacingEnum::DOWN = new FacingEnum(0, 1, 0, -1, 0);
FacingEnum* FacingEnum::UP = new FacingEnum(1, 0, 0, 1, 0);
FacingEnum* FacingEnum::NORTH = new FacingEnum(2, 3, 0, 0, -1);
FacingEnum* FacingEnum::SOUTH = new FacingEnum(3, 2, 0, 0, 1);
FacingEnum* FacingEnum::EAST = new FacingEnum(4, 5, -1, 0, 0);
FacingEnum* FacingEnum::WEST = new FacingEnum(5, 4, 1, 0, 0);
FacingEnum* FacingEnum::BY_DATA[6] = {FacingEnum::DOWN, FacingEnum::UP,
FacingEnum::NORTH, FacingEnum::SOUTH,
FacingEnum::EAST, FacingEnum::WEST};
FacingEnum::FacingEnum(int dataValue, int oppositeIndex, int stepX, int stepY,
int stepZ)
: dataValue(dataValue),
oppositeIndex(oppositeIndex),
stepX(stepX),
stepY(stepY),
stepZ(stepZ) {}
int FacingEnum::getDataValue() { return dataValue; }
FacingEnum* FacingEnum::getOpposite() { return BY_DATA[oppositeIndex]; }
int FacingEnum::getStepX() { return stepX; }
int FacingEnum::getStepY() { return stepY; }
int FacingEnum::getStepZ() { return stepZ; }
FacingEnum* FacingEnum::fromData(int data) { return BY_DATA[data % 6]; }

View file

@ -0,0 +1,31 @@
#pragma once
class FacingEnum {
public:
static FacingEnum* DOWN;
static FacingEnum* UP;
static FacingEnum* NORTH;
static FacingEnum* SOUTH;
static FacingEnum* EAST;
static FacingEnum* WEST;
private:
const int dataValue;
const int oppositeIndex;
const int stepX;
const int stepY;
const int stepZ;
static FacingEnum* BY_DATA[6];
FacingEnum(int dataValue, int oppositeIndex, int stepX, int stepY,
int stepZ);
public:
int getDataValue();
FacingEnum* getOpposite();
int getStepX();
int getStepY();
int getStepZ();
static FacingEnum* fromData(int data);
};

View file

@ -0,0 +1,440 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.item.h"
#include "../Headers/net.minecraft.world.entity.projectile.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.world.level.tile.entity.h"
#include "../Headers/net.minecraft.world.item.h"
#include "ItemDispenseBehaviors.h"
/* Arrow */
std::shared_ptr<Projectile> ArrowDispenseBehavior::getProjectile(
Level* world, Position* position) {
std::shared_ptr<Arrow> arrow = std::shared_ptr<Arrow>(
new Arrow(world, position->getX(), position->getY(), position->getZ()));
arrow->pickup = Arrow::PICKUP_ALLOWED;
return arrow;
}
/* ThrownEgg */
std::shared_ptr<Projectile> EggDispenseBehavior::getProjectile(
Level* world, Position* position) {
return std::shared_ptr<Projectile>(new ThrownEgg(
world, position->getX(), position->getY(), position->getZ()));
}
/* Snowball */
std::shared_ptr<Projectile> SnowballDispenseBehavior::getProjectile(
Level* world, Position* position) {
return std::shared_ptr<Projectile>(new Snowball(
world, position->getX(), position->getY(), position->getZ()));
}
/* Exp Bottle */
std::shared_ptr<Projectile> ExpBottleDispenseBehavior::getProjectile(
Level* world, Position* position) {
return std::shared_ptr<Projectile>(new ThrownExpBottle(
world, position->getX(), position->getY(), position->getZ()));
}
float ExpBottleDispenseBehavior::getUncertainty() {
return AbstractProjectileDispenseBehavior::getUncertainty() * .5f;
}
float ExpBottleDispenseBehavior::getPower() {
return AbstractProjectileDispenseBehavior::getPower() * 1.25f;
}
/* Thrown Potion */
ThrownPotionDispenseBehavior::ThrownPotionDispenseBehavior(int potionValue) {
m_potionValue = potionValue;
}
std::shared_ptr<Projectile> ThrownPotionDispenseBehavior::getProjectile(
Level* world, Position* position) {
return std::shared_ptr<Projectile>(
new ThrownPotion(world, position->getX(), position->getY(),
position->getZ(), m_potionValue));
}
float ThrownPotionDispenseBehavior::getUncertainty() {
return AbstractProjectileDispenseBehavior::getUncertainty() * .5f;
}
float ThrownPotionDispenseBehavior::getPower() {
return AbstractProjectileDispenseBehavior::getPower() * 1.25f;
}
/* Potion */
std::shared_ptr<ItemInstance> PotionDispenseBehavior::dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed) {
if (PotionItem::isThrowable(dispensed->getAuxValue())) {
return ThrownPotionDispenseBehavior(dispensed->getAuxValue())
.dispense(source, dispensed);
} else {
return DefaultDispenseItemBehavior::dispense(source, dispensed);
}
}
/* SpawnEggItem */
std::shared_ptr<ItemInstance> SpawnEggDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
// Spawn entity in the middle of the block in front of the dispenser
double spawnX = source->getX() + facing->getStepX();
double spawnY = source->getBlockY() + .2f; // Above pressure plates
double spawnZ = source->getZ() + facing->getStepZ();
int iResult = 0;
std::shared_ptr<Entity> entity =
SpawnEggItem::spawnMobAt(source->getWorld(), dispensed->getAuxValue(),
spawnX, spawnY, spawnZ, &iResult);
// 4J-JEV: Added in-case spawn limit is encountered.
if (entity == NULL) {
outcome = LEFT_ITEM;
return dispensed;
}
if (entity->instanceof(eTYPE_MOB) && dispensed->hasCustomHoverName()) {
std::dynamic_pointer_cast<Mob>(entity)->setCustomName(
dispensed->getHoverName());
}
outcome = ACTIVATED_ITEM;
dispensed->remove(1);
return dispensed;
}
/* Fireworks*/
std::shared_ptr<ItemInstance> FireworksDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
Level* world = source->getWorld();
if (world->countInstanceOf(eTYPE_PROJECTILE, false) >=
Level::MAX_DISPENSABLE_PROJECTILES) {
outcome = LEFT_ITEM;
return dispensed;
}
FacingEnum* facing = DispenserTile::getFacing(source->getData());
double spawnX = source->getX() + facing->getStepX();
double spawnY = source->getBlockY() + .2f;
double spawnZ = source->getZ() + facing->getStepZ();
std::shared_ptr<FireworksRocketEntity> firework =
std::shared_ptr<FireworksRocketEntity>(new FireworksRocketEntity(
world, spawnX, spawnY, spawnZ, dispensed));
source->getWorld()->addEntity(firework);
outcome = ACTIVATED_ITEM;
dispensed->remove(1);
return dispensed;
}
void FireworksDispenseBehavior::playSound(BlockSource* source,
eOUTCOME outcome) {
// 4J-JEV: This is exactly the same as the default at the moment.
// source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK,
// source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0);
DefaultDispenseItemBehavior::playSound(source, outcome);
}
/* Fireballs */
std::shared_ptr<ItemInstance> FireballDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
Level* world = source->getWorld();
if (world->countInstanceOf(eTYPE_SMALL_FIREBALL, true) >=
Level::MAX_DISPENSABLE_FIREBALLS) {
outcome = LEFT_ITEM;
return dispensed;
}
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Position* position = DispenserTile::getDispensePosition(source);
double spawnX = position->getX() + facing->getStepX() * .3f;
double spawnY = position->getY() + facing->getStepX() * .3f;
double spawnZ = position->getZ() + facing->getStepZ() * .3f;
delete position;
Random* random = world->random;
double dirX = random->nextGaussian() * .05 + facing->getStepX();
double dirY = random->nextGaussian() * .05 + facing->getStepY();
double dirZ = random->nextGaussian() * .05 + facing->getStepZ();
world->addEntity(std::shared_ptr<SmallFireball>(
new SmallFireball(world, spawnX, spawnY, spawnZ, dirX, dirY, dirZ)));
outcome = ACTIVATED_ITEM;
dispensed->remove(1);
return dispensed;
}
void FireballDispenseBehavior::playSound(BlockSource* source,
eOUTCOME outcome) {
if (outcome == ACTIVATED_ITEM) {
source->getWorld()->levelEvent(LevelEvent::SOUND_BLAZE_FIREBALL,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
} else {
DefaultDispenseItemBehavior::playSound(source, outcome);
}
}
/* Boats */
BoatDispenseBehavior::BoatDispenseBehavior() : DefaultDispenseItemBehavior() {
defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
}
BoatDispenseBehavior::~BoatDispenseBehavior() {
delete defaultDispenseItemBehavior;
}
std::shared_ptr<ItemInstance> BoatDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Level* world = source->getWorld();
// Spawn the boat 'just' outside the dispenser, it overlaps 2 'pixels' now.
double spawnX = source->getX() + facing->getStepX() * (1 + 2.0f / 16);
double spawnY = source->getY() + facing->getStepY() * (1 + 2.0f / 16);
double spawnZ = source->getZ() + facing->getStepZ() * (1 + 2.0f / 16);
int frontX = source->getBlockX() + facing->getStepX();
int frontY = source->getBlockY() + facing->getStepY();
int frontZ = source->getBlockZ() + facing->getStepZ();
Material* inFront = world->getMaterial(frontX, frontY, frontZ);
double yOffset;
// 4J: If we're at limit, just dispense item (instead of adding boat)
if (world->countInstanceOf(eTYPE_BOAT, true) >= Level::MAX_XBOX_BOATS) {
return defaultDispenseItemBehavior->dispense(source, dispensed);
}
if (Material::water == inFront) {
yOffset = 1;
} else if (Material::air == inFront &&
Material::water ==
world->getMaterial(frontX, frontY - 1, frontZ)) {
yOffset = 0;
} else {
return defaultDispenseItemBehavior->dispense(source, dispensed);
}
outcome = ACTIVATED_ITEM;
std::shared_ptr<Boat> boat = std::shared_ptr<Boat>(
new Boat(world, spawnX, spawnY + yOffset, spawnZ));
world->addEntity(boat);
dispensed->remove(1);
return dispensed;
}
void BoatDispenseBehavior::playSound(BlockSource* source, eOUTCOME outcome) {
// 4J-JEV: This is exactly the same as the default at the moment.
// source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK,
// source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0);
DefaultDispenseItemBehavior::playSound(source, outcome);
}
/* FilledBucket */
std::shared_ptr<ItemInstance> FilledBucketDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
BucketItem* bucket = (BucketItem*)dispensed->getItem();
int sourceX = source->getBlockX();
int sourceY = source->getBlockY();
int sourceZ = source->getBlockZ();
FacingEnum* facing = DispenserTile::getFacing(source->getData());
if (bucket->emptyBucket(source->getWorld(), sourceX + facing->getStepX(),
sourceY + facing->getStepY(),
sourceZ + facing->getStepZ())) {
dispensed->id = Item::bucket_empty->id;
dispensed->count = 1;
outcome = ACTIVATED_ITEM;
return dispensed;
}
return DefaultDispenseItemBehavior::dispense(source, dispensed);
}
/* EmptyBucket */
std::shared_ptr<ItemInstance> EmptyBucketDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Level* world = source->getWorld();
int targetX = source->getBlockX() + facing->getStepX();
int targetY = source->getBlockY() + facing->getStepY();
int targetZ = source->getBlockZ() + facing->getStepZ();
Material* material = world->getMaterial(targetX, targetY, targetZ);
int dataValue = world->getData(targetX, targetY, targetZ);
Item* targetType;
if (Material::water == material && dataValue == 0) {
targetType = Item::bucket_water;
} else if (Material::lava == material && dataValue == 0) {
targetType = Item::bucket_lava;
} else {
return DefaultDispenseItemBehavior::execute(source, dispensed, outcome);
}
world->removeTile(targetX, targetY, targetZ);
if (--dispensed->count == 0) {
dispensed->id = targetType->id;
dispensed->count = 1;
} else if (std::dynamic_pointer_cast<DispenserTileEntity>(
source->getEntity())
->addItem(std::shared_ptr<ItemInstance>(
new ItemInstance(targetType))) < 0) {
DefaultDispenseItemBehavior::dispense(
source,
std::shared_ptr<ItemInstance>(new ItemInstance(targetType)));
}
outcome = ACTIVATED_ITEM;
return dispensed;
}
/* Flint and Steel */
std::shared_ptr<ItemInstance> FlintAndSteelDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
outcome = ACTIVATED_ITEM;
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Level* world = source->getWorld();
int targetX = source->getBlockX() + facing->getStepX();
int targetY = source->getBlockY() + facing->getStepY();
int targetZ = source->getBlockZ() + facing->getStepZ();
if (world->isEmptyTile(targetX, targetY, targetZ)) {
world->setTileAndUpdate(targetX, targetY, targetZ, Tile::fire_Id);
if (dispensed->hurt(1, world->random)) {
dispensed->count = 0;
}
} else if (world->getTile(targetX, targetY, targetZ) == Tile::tnt_Id) {
Tile::tnt->destroy(world, targetX, targetY, targetZ, 1);
world->removeTile(targetX, targetY, targetZ);
} else {
outcome = LEFT_ITEM;
}
return dispensed;
}
void FlintAndSteelDispenseBehavior::playSound(BlockSource* source,
eOUTCOME outcome) {
if (outcome == ACTIVATED_ITEM) {
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
} else {
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
}
}
/* Dye */
std::shared_ptr<ItemInstance> DyeDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
if (dispensed->getAuxValue() == DyePowderItem::WHITE) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Level* world = source->getWorld();
int targetX = source->getBlockX() + facing->getStepX();
int targetY = source->getBlockY() + facing->getStepY();
int targetZ = source->getBlockZ() + facing->getStepZ();
if (DyePowderItem::growCrop(dispensed, world, targetX, targetY, targetZ,
false)) {
if (!world->isClientSide)
world->levelEvent(LevelEvent::PARTICLES_PLANT_GROWTH, targetX,
targetY, targetZ, 0);
outcome = ACTIVATED_ITEM;
} else {
outcome = LEFT_ITEM;
}
return dispensed;
} else {
return DefaultDispenseItemBehavior::execute(source, dispensed, outcome);
}
}
void DyeDispenseBehavior::playSound(BlockSource* source, eOUTCOME outcome) {
if (outcome == ACTIVATED_ITEM) {
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
} else {
source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL,
source->getBlockX(), source->getBlockY(),
source->getBlockZ(), 0);
}
}
/* TNT */
std::shared_ptr<ItemInstance> TntDispenseBehavior::execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome) {
FacingEnum* facing = DispenserTile::getFacing(source->getData());
Level* world = source->getWorld();
if (world->newPrimedTntAllowed() &&
app.GetGameHostOption(eGameHostOption_TNT)) {
int targetX = source->getBlockX() + facing->getStepX();
int targetY = source->getBlockY() + facing->getStepY();
int targetZ = source->getBlockZ() + facing->getStepZ();
std::shared_ptr<PrimedTnt> tnt = std::shared_ptr<PrimedTnt>(
new PrimedTnt(world, targetX + 0.5f, targetY + 0.5f, targetZ + 0.5f,
nullptr));
world->addEntity(tnt);
outcome = ACTIVATED_ITEM;
dispensed->count--;
} else {
outcome = LEFT_ITEM;
}
return dispensed;
}

View file

@ -0,0 +1,136 @@
#pragma once
#include "DefaultDispenseItemBehavior.h"
#include "AbstractProjectileDispenseBehavior.h"
class ArrowDispenseBehavior : public AbstractProjectileDispenseBehavior {
protected:
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position);
};
class EggDispenseBehavior : public AbstractProjectileDispenseBehavior {
protected:
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position);
};
class SnowballDispenseBehavior : public AbstractProjectileDispenseBehavior {
protected:
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position);
};
class ExpBottleDispenseBehavior : public AbstractProjectileDispenseBehavior {
protected:
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position);
virtual float getUncertainty();
virtual float getPower();
};
class ThrownPotionDispenseBehavior : public AbstractProjectileDispenseBehavior {
private:
int m_potionValue;
public:
ThrownPotionDispenseBehavior(int potionValue);
protected:
virtual std::shared_ptr<Projectile> getProjectile(Level* world,
Position* position);
virtual float getUncertainty();
virtual float getPower();
};
class PotionDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> dispense(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed);
};
class SpawnEggDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
};
class FireworksDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
};
class FireballDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
};
class BoatDispenseBehavior : public DefaultDispenseItemBehavior {
public:
BoatDispenseBehavior();
virtual ~BoatDispenseBehavior();
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
private:
DefaultDispenseItemBehavior* defaultDispenseItemBehavior;
};
class FilledBucketDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
};
class EmptyBucketDispenseBehavior : public DefaultDispenseItemBehavior {
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
};
class FlintAndSteelDispenseBehavior : public DefaultDispenseItemBehavior {
// bool success; // 4J-JEV: Removed because we have something cleaner for
// this now.
public:
std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
};
class DyeDispenseBehavior : public DefaultDispenseItemBehavior {
// bool success; // 4J-JEV: Removed because we have something cleaner for
// this now.
public:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
protected:
virtual void playSound(BlockSource* source, eOUTCOME outcome);
};
class TntDispenseBehavior : public DefaultDispenseItemBehavior {
protected:
virtual std::shared_ptr<ItemInstance> execute(
BlockSource* source, std::shared_ptr<ItemInstance> dispensed,
eOUTCOME& outcome);
};

View file

@ -0,0 +1,6 @@
#pragma once
#include "Source.h"
#include "Location.h"
class LocatableSource : public Source, public Location {};

View file

@ -0,0 +1,10 @@
#pragma once
#include "Position.h"
class Level;
class Location : public Position {
public:
virtual Level* getWorld() = 0;
};

View file

@ -0,0 +1,8 @@
#pragma once
class Position {
public:
virtual double getX() = 0;
virtual double getY() = 0;
virtual double getZ() = 0;
};

View file

@ -0,0 +1,23 @@
#pragma once
#include "Position.h"
class PositionImpl : public Position {
protected:
double x;
double y;
double z;
public:
PositionImpl(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
double getX() { return x; }
double getY() { return y; }
double getZ() { return z; }
};

View file

@ -0,0 +1,3 @@
#pragma once
class Source {};