the whole game
This commit is contained in:
62
src/world/Container.h
Executable file
62
src/world/Container.h
Executable file
@@ -0,0 +1,62 @@
|
||||
#ifndef NET_MINECRAFT_WORLD__Container_H__
|
||||
#define NET_MINECRAFT_WORLD__Container_H__
|
||||
|
||||
//package net.minecraft.world;
|
||||
|
||||
#include "item/ItemInstance.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Player;
|
||||
|
||||
class ContainerType {
|
||||
public:
|
||||
static const int NONE = -9;
|
||||
static const int INVENTORY = -1;
|
||||
static const int CONTAINER = 0;
|
||||
static const int WORKBENCH = 1;
|
||||
static const int FURNACE = 2;
|
||||
static const int TRAP = 3;
|
||||
static const int ENCHANTMENT = 4;
|
||||
static const int BREWING_STAND = 5;
|
||||
};
|
||||
|
||||
class Container
|
||||
{
|
||||
public:
|
||||
static const int LARGE_MAX_STACK_SIZE = 64;
|
||||
|
||||
Container(int containerType)
|
||||
: containerId(-1),
|
||||
containerType(containerType)
|
||||
{}
|
||||
virtual ~Container() {}
|
||||
|
||||
virtual ItemInstance* getItem(int slot) = 0;
|
||||
virtual void setItem(int slot, ItemInstance* item) = 0;
|
||||
virtual ItemInstance removeItem(int slot, int i) = 0;
|
||||
|
||||
virtual std::string getName() const = 0;
|
||||
virtual int getContainerSize() const = 0;
|
||||
virtual int getMaxStackSize() const = 0;
|
||||
|
||||
virtual bool stillValid(Player* player) = 0;
|
||||
|
||||
virtual void startOpen() = 0;
|
||||
virtual void stopOpen() = 0;
|
||||
|
||||
virtual std::vector<ItemInstance> getSlotCopies() {
|
||||
std::vector<ItemInstance> items;
|
||||
ItemInstance NullItem;
|
||||
for (int i = 0; i < getContainerSize(); ++i) {
|
||||
ItemInstance* item = getItem(i);
|
||||
items.push_back( item? *item : NullItem );
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
int containerId;
|
||||
int containerType;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD__Container_H__*/
|
||||
14
src/world/Difficulty.h
Executable file
14
src/world/Difficulty.h
Executable file
@@ -0,0 +1,14 @@
|
||||
#ifndef NET_MINECRAFT_WORLD__Difficulty_H__
|
||||
#define NET_MINECRAFT_WORLD__Difficulty_H__
|
||||
|
||||
//package net.minecraft.world;
|
||||
|
||||
class Difficulty {
|
||||
public:
|
||||
static const int PEACEFUL = 0;
|
||||
static const int EASY = 1;
|
||||
static const int NORMAL = 2;
|
||||
static const int HARD = 3;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD__Difficulty_H__*/
|
||||
71
src/world/Direction.cpp
Executable file
71
src/world/Direction.cpp
Executable file
@@ -0,0 +1,71 @@
|
||||
#include "Direction.h"
|
||||
#include "Facing.h"
|
||||
|
||||
const int Direction::DIRECTION_FACING[4] = {
|
||||
Facing::SOUTH,
|
||||
Facing::WEST,
|
||||
Facing::NORTH,
|
||||
Facing::EAST
|
||||
};
|
||||
const int Direction::FACING_DIRECTION[6] = {
|
||||
Direction::UNDEFINED,
|
||||
Direction::UNDEFINED,
|
||||
Direction::NORTH,
|
||||
Direction::SOUTH,
|
||||
Direction::WEST,
|
||||
Direction::EAST
|
||||
};
|
||||
const int Direction::DIRECTION_OPPOSITE[4] = {
|
||||
Direction::NORTH,
|
||||
Direction::EAST,
|
||||
Direction::SOUTH,
|
||||
Direction::WEST
|
||||
};
|
||||
|
||||
const int Direction::RELATIVE_DIRECTION_FACING[4][6] = {
|
||||
// south
|
||||
{ Facing::DOWN,
|
||||
Facing::UP,
|
||||
Facing::SOUTH,
|
||||
Facing::NORTH,
|
||||
Facing::EAST,
|
||||
Facing::WEST },
|
||||
// west
|
||||
{ Facing::DOWN,
|
||||
Facing::UP,
|
||||
Facing::EAST,
|
||||
Facing::WEST,
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH },
|
||||
// north
|
||||
{ Facing::DOWN,
|
||||
Facing::UP,
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH,
|
||||
Facing::WEST,
|
||||
Facing::EAST },
|
||||
// east
|
||||
{ Facing::DOWN,
|
||||
Facing::UP,
|
||||
Facing::WEST,
|
||||
Facing::EAST,
|
||||
Facing::SOUTH,
|
||||
Facing::NORTH }
|
||||
};
|
||||
|
||||
// declared in Facing.h
|
||||
|
||||
const int Facing::OPPOSITE_FACING[6] = {
|
||||
Facing::UP, Facing::DOWN, Facing::SOUTH, Facing::NORTH, Facing::EAST, Facing::WEST
|
||||
};
|
||||
|
||||
const int Facing::STEP_X[6] = {
|
||||
0, 0, 0, 0, -1, 1
|
||||
};
|
||||
const int Facing::STEP_Y[6] = {
|
||||
-1, 1, 0, 0, 0, 0
|
||||
};
|
||||
const int Facing::STEP_Z[6] = {
|
||||
0, 0, -1, 1, 0, 0
|
||||
};
|
||||
|
||||
28
src/world/Direction.h
Executable file
28
src/world/Direction.h
Executable file
@@ -0,0 +1,28 @@
|
||||
#ifndef NET_MINECRAFT__Direction_H__
|
||||
#define NET_MINECRAFT__Direction_H__
|
||||
|
||||
//package net.minecraft;
|
||||
|
||||
class Direction
|
||||
{
|
||||
public:
|
||||
static const int UNDEFINED = -1;
|
||||
static const int SOUTH = 0;
|
||||
static const int WEST = 1;
|
||||
static const int NORTH = 2;
|
||||
static const int EAST = 3;
|
||||
|
||||
// for [direction] it gives [tile-face]
|
||||
static const int DIRECTION_FACING[4];
|
||||
|
||||
// for a given face gives direction
|
||||
static const int FACING_DIRECTION[6];
|
||||
|
||||
// for [direction] it gives [opposite direction]
|
||||
static const int DIRECTION_OPPOSITE[4];
|
||||
|
||||
// for [direction][world-facing] it gives [tile-facing]
|
||||
static const int RELATIVE_DIRECTION_FACING[4][6];
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT__Direction_H__*/
|
||||
34
src/world/Facing.h
Executable file
34
src/world/Facing.h
Executable file
@@ -0,0 +1,34 @@
|
||||
#ifndef NET_MINECRAFT__Facing_H__
|
||||
#define NET_MINECRAFT__Facing_H__
|
||||
|
||||
//package net.minecraft;
|
||||
|
||||
class Facing
|
||||
{
|
||||
public:
|
||||
static const int DOWN = 0;
|
||||
static const int UP = 1;
|
||||
static const int NORTH = 2;
|
||||
static const int SOUTH = 3;
|
||||
static const int WEST = 4;
|
||||
static const int EAST = 5;
|
||||
|
||||
static const char* toString(int face) {
|
||||
if (face == DOWN) return "Down";
|
||||
if (face == UP ) return "Up";
|
||||
if (face == NORTH) return "North";
|
||||
if (face == SOUTH) return "South";
|
||||
if (face == WEST) return "West";
|
||||
if (face == EAST) return "East";
|
||||
return "Unknown facing";
|
||||
}
|
||||
|
||||
// implemented in Direction.cpp
|
||||
|
||||
static const int OPPOSITE_FACING[6];
|
||||
static const int STEP_X[6];
|
||||
static const int STEP_Y[6];
|
||||
static const int STEP_Z[6];
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT__Facing_H__*/
|
||||
193
src/world/Pos.h
Executable file
193
src/world/Pos.h
Executable file
@@ -0,0 +1,193 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_Pos_H__
|
||||
#define NET_MINECRAFT_WORLD_Pos_H__
|
||||
|
||||
//package net.minecraft;
|
||||
|
||||
#include <sstream>
|
||||
|
||||
class Pos
|
||||
{
|
||||
public:
|
||||
Pos()
|
||||
: x(0),
|
||||
y(0),
|
||||
z(0)
|
||||
{}
|
||||
|
||||
Pos(int x, int y, int z)
|
||||
: x(x),
|
||||
y(y),
|
||||
z(z)
|
||||
{}
|
||||
|
||||
Pos(const Pos& position)
|
||||
: x(position.x),
|
||||
y(position.y),
|
||||
z(position.z)
|
||||
{}
|
||||
|
||||
__inline bool operator==(const Pos& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && z == rhs.z;
|
||||
}
|
||||
|
||||
bool operator<(const Pos& rhs) const {
|
||||
return compareTo(rhs) < 0;
|
||||
}
|
||||
|
||||
static int createHashCode(int x, int y, int z) {
|
||||
return x + (z << 8) + (y << 16);
|
||||
}
|
||||
int hashCode() const {
|
||||
return x + (z << 8) + (y << 16);
|
||||
}
|
||||
|
||||
int compareTo(const Pos& pos) const {
|
||||
return hashCode() - pos.hashCode();
|
||||
}
|
||||
|
||||
Pos offset(int x, int y, int z) const {
|
||||
return Pos(this->x + x, this->y + y, this->z + z);
|
||||
}
|
||||
|
||||
void set(int x, int y, int z) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
}
|
||||
|
||||
void set(const Pos& pos) {
|
||||
x = pos.x;
|
||||
y = pos.y;
|
||||
z = pos.z;
|
||||
}
|
||||
|
||||
Pos above() const {
|
||||
return Pos(x, y + 1, z);
|
||||
}
|
||||
|
||||
Pos above(int steps) const {
|
||||
return Pos(x, y + steps, z);
|
||||
}
|
||||
|
||||
Pos below() const {
|
||||
return Pos(x, y - 1, z);
|
||||
}
|
||||
|
||||
Pos below(int steps) const {
|
||||
return Pos(x, y - steps, z);
|
||||
}
|
||||
|
||||
Pos north() const {
|
||||
return Pos(x, y, z - 1);
|
||||
}
|
||||
|
||||
Pos north(int steps) const {
|
||||
return Pos(x, y, z - steps);
|
||||
}
|
||||
|
||||
Pos south() const {
|
||||
return Pos(x, y, z + 1);
|
||||
}
|
||||
|
||||
Pos south(int steps) const {
|
||||
return Pos(x, y, z + steps);
|
||||
}
|
||||
|
||||
Pos west() const {
|
||||
return Pos(x - 1, y, z);
|
||||
}
|
||||
|
||||
Pos west(int steps) const {
|
||||
return Pos(x - 1, y, z);
|
||||
}
|
||||
|
||||
Pos east() const {
|
||||
return Pos(x + 1, y, z);
|
||||
}
|
||||
|
||||
Pos east(int steps) const {
|
||||
return Pos(x + steps, y, z);
|
||||
}
|
||||
|
||||
void move(int x, int y, int z) {
|
||||
this->x += x;
|
||||
this->y += y;
|
||||
this->z += z;
|
||||
}
|
||||
|
||||
void move(const Pos& pos) {
|
||||
x += pos.x;
|
||||
y += pos.y;
|
||||
z += pos.z;
|
||||
}
|
||||
|
||||
void moveX(int steps) {
|
||||
x += steps;
|
||||
}
|
||||
|
||||
void moveY(int steps) {
|
||||
y += steps;
|
||||
}
|
||||
|
||||
void moveZ(int steps) {
|
||||
z += steps;
|
||||
}
|
||||
|
||||
void moveUp(int steps) {
|
||||
y += steps;
|
||||
}
|
||||
|
||||
void moveUp() {
|
||||
++y;
|
||||
}
|
||||
|
||||
void moveDown(int steps) {
|
||||
y -= steps;
|
||||
}
|
||||
|
||||
void moveDown() {
|
||||
--y;
|
||||
}
|
||||
|
||||
void moveEast(int steps) {
|
||||
x += steps;
|
||||
}
|
||||
|
||||
void moveEast() {
|
||||
++x;
|
||||
}
|
||||
|
||||
void moveWest(int steps) {
|
||||
x -= steps;
|
||||
}
|
||||
|
||||
void moveWest() {
|
||||
--x;
|
||||
}
|
||||
|
||||
void moveNorth(int steps) {
|
||||
z -= steps;
|
||||
}
|
||||
|
||||
void moveNorth() {
|
||||
--z;
|
||||
}
|
||||
|
||||
void moveSouth(int steps) {
|
||||
z += steps;
|
||||
}
|
||||
|
||||
void moveSouth() {
|
||||
++z;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::stringstream ss;
|
||||
ss << "Pos(" << x << "," << y << "," << z << ")";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int x, y, z;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_Pos_H__*/
|
||||
36
src/world/PosTranslator.h
Executable file
36
src/world/PosTranslator.h
Executable file
@@ -0,0 +1,36 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_PosTranslator_H__
|
||||
#define NET_MINECRAFT_WORLD_PosTranslator_H__
|
||||
|
||||
//package net.minecraft;
|
||||
|
||||
class IPosTranslator {
|
||||
public:
|
||||
virtual ~IPosTranslator() {}
|
||||
virtual void to(int& x, int& y, int& z) = 0;
|
||||
virtual void to(float& x, float& y, float& z) = 0;
|
||||
|
||||
virtual void from(int& x, int& y, int& z) = 0;
|
||||
virtual void from(float& x, float& y, float& z) = 0;
|
||||
};
|
||||
|
||||
class OffsetPosTranslator: public IPosTranslator {
|
||||
public:
|
||||
OffsetPosTranslator()
|
||||
: xo(0),
|
||||
yo(0),
|
||||
zo(0)
|
||||
{}
|
||||
OffsetPosTranslator(float xo, float yo, float zo)
|
||||
: xo(xo),
|
||||
yo(yo),
|
||||
zo(zo)
|
||||
{}
|
||||
void to (float& x, float& y, float& z) { x += xo; y += yo; z += zo; }
|
||||
void to (int& x, int& y, int& z) { x += (int)xo; y += (int)yo; z += (int)zo; }
|
||||
void from(float& x, float& y, float& z) { x -= xo; y -= yo; z -= zo; }
|
||||
void from(int& x, int& y, int& z) { x -= (int)xo; y -= (int)yo; z -= (int)zo; }
|
||||
|
||||
float xo, yo, zo;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_PosTranslator_H__*/
|
||||
53
src/world/entity/AgableMob.cpp
Executable file
53
src/world/entity/AgableMob.cpp
Executable file
@@ -0,0 +1,53 @@
|
||||
#include "AgableMob.h"
|
||||
|
||||
AgableMob::AgableMob( Level* level )
|
||||
: super(level),
|
||||
age(-1)
|
||||
{
|
||||
entityData.define(DATA_FLAGS_ID, (SynchedEntityData::TypeChar)0);
|
||||
setAge(0);
|
||||
}
|
||||
|
||||
int AgableMob::getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
void AgableMob::setAge( int age ) {
|
||||
if (this->age < 0 && age >= 0) {
|
||||
entityData.clearFlag<SynchedEntityData::TypeChar>(DATA_FLAGS_ID, DATAFLAG_ISBABY);
|
||||
}
|
||||
else if (this->age >= 0 && age < 0) {
|
||||
entityData.setFlag<SynchedEntityData::TypeChar>(DATA_FLAGS_ID, DATAFLAG_ISBABY);
|
||||
}
|
||||
this->age = age;
|
||||
}
|
||||
|
||||
void AgableMob::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
super::addAdditonalSaveData(tag);
|
||||
tag->putInt("Age", getAge());
|
||||
}
|
||||
|
||||
void AgableMob::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
super::readAdditionalSaveData(tag);
|
||||
setAge(tag->getInt("Age"));
|
||||
}
|
||||
|
||||
void AgableMob::aiStep() {
|
||||
super::aiStep();
|
||||
|
||||
//@note: keeping this for now, since we don't use breeding anyway
|
||||
// and it feels better to have animals at age 0 then 99999999
|
||||
// if we decide to actually use it.
|
||||
if (age < 0)
|
||||
setAge(age + 1);
|
||||
else if (age > 0)
|
||||
setAge(age - 1);
|
||||
}
|
||||
|
||||
bool AgableMob::isBaby() {
|
||||
if (!level->isClientSide) {
|
||||
return age < 0;
|
||||
} else {
|
||||
return entityData.getFlag<SynchedEntityData::TypeChar>(DATA_FLAGS_ID, DATAFLAG_ISBABY);
|
||||
}
|
||||
}
|
||||
30
src/world/entity/AgableMob.h
Executable file
30
src/world/entity/AgableMob.h
Executable file
@@ -0,0 +1,30 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__AgableMob_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__AgableMob_H__
|
||||
|
||||
#include "PathfinderMob.h"
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
class AgableMob: public PathfinderMob
|
||||
{
|
||||
typedef PathfinderMob super;
|
||||
public:
|
||||
AgableMob(Level* level);
|
||||
|
||||
int getAge();
|
||||
void setAge(int age);
|
||||
bool isBaby();
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
void aiStep();
|
||||
private:
|
||||
int age;
|
||||
|
||||
static const int DATA_FLAGS_ID = 14;
|
||||
// Flags values are bit shifted
|
||||
static const int DATAFLAG_ISBABY = 0;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__AgableMob_H__*/
|
||||
9
src/world/entity/Creature.h
Executable file
9
src/world/entity/Creature.h
Executable file
@@ -0,0 +1,9 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__Creature_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__Creature_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
class Creature {
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__Creature_H__*/
|
||||
963
src/world/entity/Entity.cpp
Executable file
963
src/world/entity/Entity.cpp
Executable file
@@ -0,0 +1,963 @@
|
||||
#include "Entity.h"
|
||||
#include "EntityPos.h"
|
||||
#include "../level/Level.h"
|
||||
#include "../level/tile/LiquidTile.h"
|
||||
#include "item/ItemEntity.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
#include "../../nbt/CompoundTag.h"
|
||||
#include "../../util/PerfTimer.h"
|
||||
|
||||
int
|
||||
Entity::entityCounter = 0;
|
||||
Random
|
||||
Entity::sharedRandom(getEpochTimeS());
|
||||
|
||||
Entity::Entity( Level* level )
|
||||
: level(level),
|
||||
viewScale(1.0f),
|
||||
blocksBuilding(false),
|
||||
onGround(false),
|
||||
wasInWater(false),
|
||||
collision(false),
|
||||
hurtMarked(false),
|
||||
slide(true),
|
||||
isStuckInWeb(false),
|
||||
removed(false),
|
||||
reallyRemoveIfPlayer(false),
|
||||
canRemove(true), //@todo: remove
|
||||
noPhysics(false),
|
||||
firstTick(true),
|
||||
|
||||
bbWidth(0.6f),
|
||||
bbHeight(1.8f),
|
||||
heightOffset(0 / 16.0f),
|
||||
bb(0,0,0,0,0,0),
|
||||
|
||||
ySlideOffset(0),
|
||||
fallDistance(0),
|
||||
footSize(0),
|
||||
invulnerableTime(0),
|
||||
pushthrough(0),
|
||||
airCapacity(TOTAL_AIR_SUPPLY),
|
||||
airSupply(TOTAL_AIR_SUPPLY),
|
||||
|
||||
xOld(0),yOld(0),zOld(0),
|
||||
horizontalCollision(false), verticalCollision(false),
|
||||
|
||||
x(0), y(0), z(0),
|
||||
xo(0),yo(0),zo(0),xd(0),yd(0),zd(0),
|
||||
xRot(0), yRot(0),
|
||||
xRotO(0), yRotO(0),
|
||||
|
||||
xChunk(0), yChunk(0), zChunk(0),
|
||||
inChunk(false),
|
||||
|
||||
fireImmune(false),
|
||||
onFire(0),
|
||||
flameTime(1),
|
||||
walkDist(0), walkDistO(0),
|
||||
tickCount(0),
|
||||
entityRendererId(ER_DEFAULT_RENDERER),
|
||||
nextStep(1),
|
||||
makeStepSound(true),
|
||||
invisible(false)
|
||||
{
|
||||
_init();
|
||||
|
||||
entityId = ++entityCounter;
|
||||
|
||||
//ref = Ref<Entity>::create(this);
|
||||
|
||||
setPos(0, 0, 0);
|
||||
}
|
||||
|
||||
Entity::~Entity() {
|
||||
//if (ref->isUnique())
|
||||
// delete ref;
|
||||
}
|
||||
|
||||
SynchedEntityData* Entity::getEntityData() {
|
||||
return NULL;
|
||||
}
|
||||
const SynchedEntityData* Entity::getEntityData() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Entity::isInWall() {
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(y + getHeadHeight());
|
||||
int zt = Mth::floor(z);
|
||||
return level->isSolidBlockingTile(xt, yt, zt);
|
||||
}
|
||||
|
||||
void Entity::resetPos(bool clearMore) {
|
||||
if (level == NULL) return;
|
||||
while (y > 0) {
|
||||
setPos(x, y, z);
|
||||
if (level->getCubes(this, bb).size() == 0) break;
|
||||
y += 1;
|
||||
}
|
||||
|
||||
xd = yd = zd = 0;
|
||||
xRot = 0;
|
||||
}
|
||||
|
||||
bool Entity::isInWater() {
|
||||
return level->checkAndHandleWater(bb.grow(0, -0.4f, 0), Material::water, this);
|
||||
}
|
||||
|
||||
bool Entity::isInLava() {
|
||||
return level->containsMaterial(bb.grow(-0.1f, -0.4f, -0.1f), Material::lava);
|
||||
}
|
||||
|
||||
bool Entity::isFree(float xa, float ya, float za, float grow) {
|
||||
AABB box = bb.grow(grow, grow, grow).cloneMove(xa, ya, za);
|
||||
const std::vector<AABB>& aABBs = level->getCubes(this, box);
|
||||
if (aABBs.size() > 0) return false;
|
||||
if (level->containsAnyLiquid(box)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Entity::isFree(float xa, float ya, float za) {
|
||||
AABB box = bb.cloneMove(xa, ya, za);
|
||||
const std::vector<AABB>& aABBs = level->getCubes(this, box);
|
||||
if (aABBs.size() > 0) return false;
|
||||
if (level->containsAnyLiquid(box)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//static void __attribute__((noinline)) setPositionFromBbox(Entity* e) { // @RPI
|
||||
// const AABB& bb = e->bb;
|
||||
// e->x = (e->bb.x0 + e->bb.x1) / 2.0f;
|
||||
// e->y = bb.y0 + e->heightOffset - e->ySlideOffset;
|
||||
// e->z = (bb.z0 + bb.z1) / 2.0f;
|
||||
//}
|
||||
|
||||
/*public*/
|
||||
void Entity::move(float xa, float ya, float za) {
|
||||
//if (std::abs(xa) + std::abs(ya) + std::abs(za) < 0.00001f) //@RPI
|
||||
// return;
|
||||
|
||||
if (noPhysics) {
|
||||
bb.move(xa, ya, za);
|
||||
x = (bb.x0 + bb.x1) / 2.0f;
|
||||
y = bb.y0 + heightOffset - ySlideOffset;
|
||||
z = (bb.z0 + bb.z1) / 2.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
TIMER_PUSH("move");
|
||||
|
||||
float xo = x;
|
||||
float zo = z;
|
||||
|
||||
if (isStuckInWeb) {
|
||||
isStuckInWeb = false;
|
||||
|
||||
xa *= .25f;
|
||||
ya *= .05f;
|
||||
za *= .25f;
|
||||
xd = .0f;
|
||||
yd = .0f;
|
||||
zd = .0f;
|
||||
}
|
||||
|
||||
float xaOrg = xa;
|
||||
float yaOrg = ya;
|
||||
float zaOrg = za;
|
||||
|
||||
AABB bbOrg = bb;
|
||||
|
||||
bool sneaking = onGround && isSneaking();
|
||||
|
||||
if (sneaking) {
|
||||
float d = 0.05f;
|
||||
while (xa != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, 0)).empty()) {
|
||||
if (xa < d && xa >= -d) xa = 0;
|
||||
else if (xa > 0) xa -= d;
|
||||
else xa += d;
|
||||
xaOrg = xa;
|
||||
}
|
||||
while (za != 0 && level->getCubes(this, bb.cloneMove(0, -1.0, za)).empty()) {
|
||||
if (za < d && za >= -d) za = 0;
|
||||
else if (za > 0) za -= d;
|
||||
else za += d;
|
||||
zaOrg = za;
|
||||
}
|
||||
|
||||
while (xa != 0 && za != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, za)).empty()) {
|
||||
if (xa < d && xa >= -d) xa = 0;
|
||||
else if (xa > 0) xa -= d;
|
||||
else xa += d;
|
||||
if (za < d && za >= -d) za = 0;
|
||||
else if (za > 0) za -= d;
|
||||
else za += d;
|
||||
xaOrg = xa;
|
||||
zaOrg = za;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<AABB>& aABBs = level->getCubes(this, bb.expand(xa, ya, za));
|
||||
|
||||
// LAND FIRST, then x and z
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
ya = aABBs[i].clipYCollide(bb, ya);
|
||||
bb.move(0, ya, 0);
|
||||
|
||||
if (!slide && yaOrg != ya) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
bool og = onGround || (yaOrg != ya && yaOrg < 0);
|
||||
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
xa = aABBs[i].clipXCollide(bb, xa);
|
||||
|
||||
bb.move(xa, 0, 0);
|
||||
|
||||
if (!slide && xaOrg != xa) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
za = aABBs[i].clipZCollide(bb, za);
|
||||
bb.move(0, 0, za);
|
||||
|
||||
if (!slide && zaOrg != za) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
if (footSize > 0 && og && (ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) {
|
||||
|
||||
float xaN = xa;
|
||||
float yaN = ya;
|
||||
float zaN = za;
|
||||
|
||||
xa = xaOrg;
|
||||
ya = footSize;
|
||||
za = zaOrg;
|
||||
|
||||
AABB normal = bb;
|
||||
bb.set(bbOrg);
|
||||
aABBs = level->getCubes(this, bb.expand(xa, ya, za));
|
||||
|
||||
// LAND FIRST, then x and z
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
ya = aABBs[i].clipYCollide(bb, ya);
|
||||
bb.move(0, ya, 0);
|
||||
|
||||
if (!slide && yaOrg != ya) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
xa = aABBs[i].clipXCollide(bb, xa);
|
||||
bb.move(xa, 0, 0);
|
||||
|
||||
if (!slide && xaOrg != xa) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < aABBs.size(); i++)
|
||||
za = aABBs[i].clipZCollide(bb, za);
|
||||
bb.move(0, 0, za);
|
||||
|
||||
if (!slide && zaOrg != za) {
|
||||
xa = ya = za = 0;
|
||||
}
|
||||
|
||||
if (xaN * xaN + zaN * zaN >= xa * xa + za * za) {
|
||||
xa = xaN;
|
||||
ya = yaN;
|
||||
za = zaN;
|
||||
bb.set(normal);
|
||||
} else {
|
||||
ySlideOffset += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_POP_PUSH("rest");
|
||||
|
||||
x = (bb.x0 + bb.x1) / 2.0f;
|
||||
y = bb.y0 + heightOffset - ySlideOffset;
|
||||
z = (bb.z0 + bb.z1) / 2.0f;
|
||||
|
||||
horizontalCollision = (xaOrg != xa) || (zaOrg != za);
|
||||
verticalCollision = (yaOrg != ya);
|
||||
onGround = yaOrg != ya && yaOrg < 0;
|
||||
collision = horizontalCollision || verticalCollision;
|
||||
checkFallDamage(ya, onGround);
|
||||
|
||||
if (xaOrg != xa) xd = 0;
|
||||
if (yaOrg != ya) yd = 0;
|
||||
if (zaOrg != za) zd = 0;
|
||||
|
||||
float xm = x - xo;
|
||||
float zm = z - zo;
|
||||
|
||||
if (makeStepSound && !sneaking) {
|
||||
walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6f;
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(y - 0.2f - this->heightOffset);
|
||||
int zt = Mth::floor(z);
|
||||
|
||||
int t = level->getTile(xt, yt, zt);
|
||||
if (t == 0) {
|
||||
int under = level->getTile(xt, yt-1, zt);
|
||||
if (Tile::fence->id == under || Tile::fenceGate->id == under) {
|
||||
t = under;
|
||||
}
|
||||
}
|
||||
|
||||
if (walkDist > nextStep && t > 0) {
|
||||
nextStep = ((int) walkDist) + 1;
|
||||
playStepSound(xt, yt, zt, t);
|
||||
//Tile::tiles[t]->stepOn(level, xt, yt, zt, this); //@todo: step
|
||||
}
|
||||
}
|
||||
|
||||
int x0 = Mth::floor(bb.x0);
|
||||
int y0 = Mth::floor(bb.y0);
|
||||
int z0 = Mth::floor(bb.z0);
|
||||
int x1 = Mth::floor(bb.x1);
|
||||
int y1 = Mth::floor(bb.y1);
|
||||
int z1 = Mth::floor(bb.z1);
|
||||
|
||||
if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) {
|
||||
for (int x = x0; x <= x1; x++)
|
||||
for (int y = y0; y <= y1; y++)
|
||||
for (int z = z0; z <= z1; z++) {
|
||||
int t = level->getTile(x, y, z);
|
||||
if (t > 0) {
|
||||
Tile::tiles[t]->entityInside(level, x, y, z, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ySlideOffset *= 0.4f;
|
||||
|
||||
bool water = this->isInWater();
|
||||
if (level->containsFireTile(bb)) {
|
||||
burn(1);
|
||||
if (!water) {
|
||||
onFire++;
|
||||
if (onFire == 0) onFire = 20 * 15;
|
||||
}
|
||||
} else {
|
||||
if (onFire <= 0) {
|
||||
onFire = -flameTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (water && onFire > 0) {
|
||||
//level.playSound(this-> "random.fizz", 0.7f, 1.6f + (random.nextFloat() - random.nextFloat()) * 0.4f);
|
||||
onFire = -flameTime;
|
||||
}
|
||||
|
||||
TIMER_POP();
|
||||
}
|
||||
|
||||
void Entity::makeStuckInWeb() {
|
||||
isStuckInWeb = true;
|
||||
fallDistance = 0;
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
bool Entity::isUnderLiquid(const Material* material) {
|
||||
float yp = y + getHeadHeight();
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor((float)Mth::floor(yp));
|
||||
int zt = Mth::floor(z);
|
||||
int t = level->getTile(xt, yt, zt);
|
||||
if (t != 0 && Tile::tiles[t]->material == material) {
|
||||
float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f;
|
||||
float h = yt + 1 - hh;
|
||||
return yp < h;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*protected virtual*/
|
||||
void Entity::setPos(EntityPos* pos)
|
||||
{
|
||||
if (pos->move) setPos(pos->x, pos->y, pos->z);
|
||||
else setPos(x, y, z);
|
||||
|
||||
if (pos->rot) setRot(pos->yRot, pos->xRot);
|
||||
else setRot(yRot, xRot);
|
||||
}
|
||||
|
||||
void Entity::setPos( float x, float y, float z )
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
float w = bbWidth / 2;
|
||||
float h = bbHeight;
|
||||
bb.set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w);
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
float Entity::getBrightness(float a) {
|
||||
int xTile = Mth::floor(x);
|
||||
|
||||
float hh = (bb.y1 - bb.y0) * 0.66f;
|
||||
int yTile = Mth::floor(y - this->heightOffset + hh);
|
||||
int zTile = Mth::floor(z);
|
||||
if (level->hasChunksAt(Mth::floor(bb.x0), Mth::floor(bb.y0), Mth::floor(bb.z0), Mth::floor(bb.x1), Mth::floor(bb.y1), Mth::floor(bb.z1))) {
|
||||
return level->getBrightness(xTile, yTile, zTile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Entity::operator==( Entity& rhs )
|
||||
{
|
||||
return entityId == rhs.entityId;
|
||||
}
|
||||
|
||||
int Entity::hashCode()
|
||||
{
|
||||
return entityId;
|
||||
}
|
||||
|
||||
void Entity::remove()
|
||||
{
|
||||
removed = true;
|
||||
}
|
||||
|
||||
void Entity::setSize( float w, float h )
|
||||
{
|
||||
bbWidth = w;
|
||||
bbHeight = h;
|
||||
}
|
||||
|
||||
void Entity::setRot( float yRot, float xRot )
|
||||
{
|
||||
this->yRot = yRotO = yRot;
|
||||
this->xRot = xRotO = xRot;
|
||||
}
|
||||
|
||||
void Entity::turn( float xo, float yo )
|
||||
{
|
||||
float xRotOld = xRot;
|
||||
float yRotOld = yRot;
|
||||
|
||||
yRot += xo * 0.15f;
|
||||
xRot -= yo * 0.15f;
|
||||
if (xRot < -90) xRot = -90;
|
||||
if (xRot > 90) xRot = 90;
|
||||
|
||||
xRotO += xRot - xRotOld;
|
||||
yRotO += yRot - yRotOld;
|
||||
}
|
||||
|
||||
void Entity::interpolateTurn( float xo, float yo )
|
||||
{
|
||||
yRot += xo * 0.15f;
|
||||
xRot -= yo * 0.15f;
|
||||
if (xRot < -90) xRot = -90;
|
||||
if (xRot > 90) xRot = 90;
|
||||
}
|
||||
|
||||
void Entity::tick()
|
||||
{
|
||||
baseTick();
|
||||
}
|
||||
|
||||
void Entity::baseTick()
|
||||
{
|
||||
TIMER_PUSH("entityBaseTick");
|
||||
|
||||
tickCount++;
|
||||
walkDistO = walkDist;
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
xRotO = xRot;
|
||||
yRotO = yRot;
|
||||
|
||||
if (isInWater()) {
|
||||
if (!wasInWater && !firstTick) {
|
||||
float speed = sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f;
|
||||
if (speed > 1) speed = 1;
|
||||
level->playSound(this, "random.splash", speed, 1 + (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.4f);
|
||||
float yt = floorf(bb.y0);
|
||||
for (int i = 0; i < 1 + bbWidth * 20; i++) {
|
||||
float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
|
||||
float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
|
||||
level->addParticle(PARTICLETYPE(bubble), x + xo, yt + 1, z + zo, xd, yd - sharedRandom.nextFloat() * 0.2f, zd);
|
||||
}
|
||||
//for (int i = 0; i < 1 + bbWidth * 20; i++) {
|
||||
// float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
|
||||
// float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth;
|
||||
// level->addParticle(PARTICLETYPE(splash), x + xo, yt + 1, z + zo, xd, yd, zd);
|
||||
//}
|
||||
}
|
||||
fallDistance = 0;
|
||||
wasInWater = true;
|
||||
onFire = 0;
|
||||
} else {
|
||||
wasInWater = false;
|
||||
}
|
||||
|
||||
if (level->isClientSide) {
|
||||
onFire = 0;
|
||||
} else {
|
||||
if (onFire > 0) {
|
||||
if (fireImmune) {
|
||||
onFire -= 4;
|
||||
if (onFire < 0) onFire = 0;
|
||||
} else {
|
||||
if (onFire % 20 == 0) {
|
||||
hurt(NULL, 1);
|
||||
}
|
||||
onFire--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isInLava()) {
|
||||
lavaHurt();
|
||||
}
|
||||
|
||||
if (y < -64) {
|
||||
outOfWorld();
|
||||
}
|
||||
|
||||
//if (!level->isOnline) {
|
||||
// setSharedFlag(FLAG_ONFIRE, onFire > 0);
|
||||
//}
|
||||
|
||||
firstTick = false;
|
||||
TIMER_POP();
|
||||
}
|
||||
|
||||
void Entity::outOfWorld()
|
||||
{
|
||||
remove();
|
||||
}
|
||||
|
||||
void Entity::checkFallDamage( float ya, bool onGround )
|
||||
{
|
||||
if (onGround) {
|
||||
if (fallDistance > 0) {
|
||||
if(isMob()) {
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(y - 0.2f - heightOffset);
|
||||
int zt = Mth::floor(z);
|
||||
int t = level->getTile(xt, yt, zt);
|
||||
if (t == 0 && level->getTile(xt, yt - 1, zt) == Tile::fence->id) {
|
||||
t = level->getTile(xt, yt - 1, zt);
|
||||
}
|
||||
|
||||
if (t > 0) {
|
||||
Tile::tiles[t]->fallOn(level, xt, yt, zt, this, fallDistance);
|
||||
}
|
||||
}
|
||||
causeFallDamage(fallDistance);
|
||||
fallDistance = 0;
|
||||
}
|
||||
} else {
|
||||
if (ya < 0) fallDistance -= ya;
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::causeFallDamage( float fallDamage2 )
|
||||
{
|
||||
}
|
||||
|
||||
float Entity::getHeadHeight()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Entity::moveRelative( float xa, float za, float speed )
|
||||
{
|
||||
float dist = sqrt(xa * xa + za * za);
|
||||
if (dist < 0.01f) return;
|
||||
|
||||
if (dist < 1) dist = 1;
|
||||
dist = speed / dist;
|
||||
xa *= dist;
|
||||
za *= dist;
|
||||
|
||||
float sin_ = (float) sin(yRot * Mth::PI / 180);
|
||||
float cos_ = (float) cos(yRot * Mth::PI / 180);
|
||||
|
||||
xd += xa * cos_ - za * sin_;
|
||||
zd += za * cos_ + xa * sin_;
|
||||
}
|
||||
|
||||
void Entity::setLevel( Level* level )
|
||||
{
|
||||
this->level = level;
|
||||
}
|
||||
|
||||
void Entity::moveTo( float x, float y, float z, float yRot, float xRot )
|
||||
{
|
||||
this->xOld = this->xo = this->x = x;
|
||||
this->yOld = this->yo = this->y = y + heightOffset;
|
||||
this->zOld = this->zo = this->z = z;
|
||||
this->yRot = this->yRotO = yRot;
|
||||
this->xRot = this->xRotO = xRot;
|
||||
this->setPos(this->x, this->y, this->z);
|
||||
}
|
||||
|
||||
float Entity::distanceTo( Entity* e )
|
||||
{
|
||||
float xd = (float) (x - e->x);
|
||||
float yd = (float) (y - e->y);
|
||||
float zd = (float) (z - e->z);
|
||||
return sqrt(xd * xd + yd * yd + zd * zd);
|
||||
}
|
||||
|
||||
float Entity::distanceTo( float x2, float y2, float z2 )
|
||||
{
|
||||
float xd = (x - x2);
|
||||
float yd = (y - y2);
|
||||
float zd = (z - z2);
|
||||
return sqrt(xd * xd + yd * yd + zd * zd);
|
||||
}
|
||||
|
||||
float Entity::distanceToSqr( float x2, float y2, float z2 )
|
||||
{
|
||||
float xd = (x - x2);
|
||||
float yd = (y - y2);
|
||||
float zd = (z - z2);
|
||||
return xd * xd + yd * yd + zd * zd;
|
||||
}
|
||||
|
||||
float Entity::distanceToSqr( Entity* e )
|
||||
{
|
||||
float xd = x - e->x;
|
||||
float yd = y - e->y;
|
||||
float zd = z - e->z;
|
||||
return xd * xd + yd * yd + zd * zd;
|
||||
}
|
||||
|
||||
void Entity::playerTouch( Player* player )
|
||||
{
|
||||
}
|
||||
|
||||
void Entity::push( Entity* e )
|
||||
{
|
||||
float xa = e->x - x;
|
||||
float za = e->z - z;
|
||||
|
||||
float dd = Mth::absMax(xa, za);
|
||||
|
||||
if (dd >= 0.01f) {
|
||||
dd = sqrt(dd);
|
||||
xa /= dd;
|
||||
za /= dd;
|
||||
|
||||
float pow = 1 / dd;
|
||||
if (pow > 1) pow = 1;
|
||||
xa *= pow;
|
||||
za *= pow;
|
||||
|
||||
xa *= 0.05f;
|
||||
za *= 0.05f;
|
||||
|
||||
xa *= 1 - pushthrough;
|
||||
za *= 1 - pushthrough;
|
||||
|
||||
this->push(-xa, 0, -za);
|
||||
e->push(xa, 0, za);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::push( float xa, float ya, float za )
|
||||
{
|
||||
xd += xa;
|
||||
yd += ya;
|
||||
zd += za;
|
||||
}
|
||||
|
||||
void Entity::markHurt()
|
||||
{
|
||||
this->hurtMarked = true;
|
||||
}
|
||||
|
||||
bool Entity::hurt( Entity* source, int damage )
|
||||
{
|
||||
markHurt();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::reset() {
|
||||
this->_init();
|
||||
}
|
||||
void Entity::_init() {
|
||||
xo = xOld = x;
|
||||
yo = yOld = y;
|
||||
zo = zOld = z;
|
||||
xRotO = xRot;
|
||||
yRotO = yRot;
|
||||
onFire = 0;
|
||||
removed = false;
|
||||
fallDistance = 0;
|
||||
}
|
||||
|
||||
bool Entity::intersects( float x0, float y0, float z0, float x1, float y1, float z1 )
|
||||
{
|
||||
return bb.intersects(x0, y0, z0, x1, y1, z1);
|
||||
}
|
||||
|
||||
bool Entity::isPickable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Entity::isPushable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Entity::isShootable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::awardKillScore( Entity* victim, int score )
|
||||
{
|
||||
}
|
||||
|
||||
bool Entity::shouldRender( Vec3& c )
|
||||
{
|
||||
if (invisible) return false;
|
||||
float xd = x - c.x;
|
||||
float yd = y - c.y;
|
||||
float zd = z - c.z;
|
||||
float distance = xd * xd + yd * yd + zd * zd;
|
||||
return shouldRenderAtSqrDistance(distance);
|
||||
}
|
||||
|
||||
bool Entity::shouldRenderAtSqrDistance( float distance )
|
||||
{
|
||||
float size = bb.getSize();
|
||||
size *= 64.0f * viewScale;
|
||||
return distance < size * size;
|
||||
}
|
||||
|
||||
bool Entity::isCreativeModeAllowed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float Entity::getShadowHeightOffs()
|
||||
{
|
||||
return bbHeight / 2;
|
||||
}
|
||||
|
||||
bool Entity::isAlive()
|
||||
{
|
||||
return !removed;
|
||||
}
|
||||
|
||||
bool Entity::interact( Player* player )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::lerpTo( float x, float y, float z, float yRot, float xRot, int steps )
|
||||
{
|
||||
setPos(x, y, z);
|
||||
setRot(yRot, xRot);
|
||||
}
|
||||
|
||||
float Entity::getPickRadius()
|
||||
{
|
||||
return 0.1f;
|
||||
}
|
||||
|
||||
void Entity::lerpMotion( float xd, float yd, float zd )
|
||||
{
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
}
|
||||
|
||||
void Entity::animateHurt()
|
||||
{
|
||||
}
|
||||
|
||||
void Entity::setEquippedSlot( int slot, int item, int auxValue )
|
||||
{
|
||||
}
|
||||
|
||||
bool Entity::isSneaking()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Entity::isPlayer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Entity::lavaHurt() {
|
||||
if (fireImmune) {
|
||||
} else {
|
||||
hurt(NULL, 4);
|
||||
onFire = 30 * SharedConstants::TicksPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
// AABB getCollideBox() {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
void Entity::burn(int dmg) {
|
||||
if (!fireImmune) {
|
||||
hurt(NULL, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
// std::string getTexture() {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
bool Entity::save(CompoundTag* entityTag) {
|
||||
int id = getEntityTypeId();
|
||||
|
||||
if (removed || id == 0) {
|
||||
return false;
|
||||
}
|
||||
entityTag->putInt("id", id);
|
||||
saveWithoutId(entityTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Entity::saveWithoutId(CompoundTag* entityTag) {
|
||||
entityTag->put("Pos", ListTagFloatAdder (x) (y) (z).tag);
|
||||
entityTag->put("Motion", ListTagFloatAdder (xd) (yd) (zd).tag);
|
||||
entityTag->put("Rotation", ListTagFloatAdder (yRot) (xRot).tag);
|
||||
|
||||
entityTag->putFloat("FallDistance", fallDistance);
|
||||
entityTag->putShort("Fire", (short) onFire);
|
||||
entityTag->putShort("Air", (short) airSupply);
|
||||
entityTag->putBoolean("OnGround", onGround);
|
||||
|
||||
addAdditonalSaveData(entityTag);
|
||||
}
|
||||
|
||||
bool Entity::load( CompoundTag* tag )
|
||||
{
|
||||
ListTag* pos = tag->getList("Pos");
|
||||
ListTag* motion = tag->getList("Motion");
|
||||
ListTag* rotation = tag->getList("Rotation");
|
||||
setPos(0, 0, 0);
|
||||
|
||||
xd = motion->getFloat(0);
|
||||
yd = motion->getFloat(1);
|
||||
zd = motion->getFloat(2);
|
||||
|
||||
if (Mth::abs(xd) > 10.0) {
|
||||
xd = 0;
|
||||
}
|
||||
if (Mth::abs(yd) > 10.0) {
|
||||
yd = 0;
|
||||
}
|
||||
if (Mth::abs(zd) > 10.0) {
|
||||
zd = 0;
|
||||
}
|
||||
|
||||
float xx = pos->getFloat(0);
|
||||
float yy = pos->getFloat(1);
|
||||
float zz = pos->getFloat(2);
|
||||
|
||||
// Add a small padding if standing next to the world edges
|
||||
const float padding = bbWidth * 0.5f + 0.001f;
|
||||
xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding);
|
||||
zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding);
|
||||
|
||||
xo = xOld = x = xx;
|
||||
yo = yOld = y = yy;
|
||||
zo = zOld = z = zz;
|
||||
|
||||
yRotO = yRot = fmod( rotation->getFloat(0), 360.0f);
|
||||
xRotO = xRot = fmod( rotation->getFloat(1), 360.0f);
|
||||
|
||||
fallDistance= tag->getFloat("FallDistance");
|
||||
onFire = tag->getShort("Fire");
|
||||
airSupply = tag->getShort("Air");
|
||||
onGround = tag->getBoolean("OnGround");
|
||||
|
||||
setPos(x, y, z);
|
||||
|
||||
readAdditionalSaveData(tag);
|
||||
return (tag->errorState == 0);
|
||||
}
|
||||
|
||||
// /*protected*/ const String getEncodeId() {
|
||||
// return EntityIO.getEncodeId(this->;
|
||||
// }
|
||||
|
||||
ItemEntity* Entity::spawnAtLocation(int resource, int count) {
|
||||
return spawnAtLocation(resource, count, 0);
|
||||
}
|
||||
|
||||
ItemEntity* Entity::spawnAtLocation(int resource, int count, float yOffs) {
|
||||
return spawnAtLocation(new ItemInstance(resource, count, 0), yOffs);
|
||||
}
|
||||
|
||||
ItemEntity* Entity::spawnAtLocation(ItemInstance* itemInstance, float yOffs) {
|
||||
ItemEntity* ie = new ItemEntity(level, x, y + yOffs, z, *itemInstance);
|
||||
|
||||
{ //@todo:itementity
|
||||
delete itemInstance;
|
||||
itemInstance = NULL;
|
||||
}
|
||||
|
||||
ie->throwTime = 10;
|
||||
level->addEntity(ie);
|
||||
return ie;
|
||||
}
|
||||
|
||||
bool Entity::isOnFire() {
|
||||
return onFire > 0;// || getSharedFlag(FLAG_ONFIRE);
|
||||
}
|
||||
|
||||
bool Entity::interactPreventDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// AABB getCollideAgainstBox(Entity entity) {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
// Vec3 getLookAngle() {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
// void prepareCustomTextures() {
|
||||
// }
|
||||
|
||||
// ItemInstance[] getEquipmentSlots() {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
bool Entity::isItemEntity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Entity::isHangingEntity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int Entity::getAuxData() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Entity::playStepSound( int xt, int yt, int zt, int t ) {
|
||||
const Tile::SoundType* soundType = Tile::tiles[t]->soundType;
|
||||
if (level->getTile(xt, yt + 1, zt) == Tile::topSnow->id) {
|
||||
soundType = Tile::topSnow->soundType;
|
||||
level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); // was * 0.15f
|
||||
} else if (!Tile::tiles[t]->material->isLiquid()) {
|
||||
level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch());
|
||||
}
|
||||
}
|
||||
226
src/world/entity/Entity.h
Executable file
226
src/world/entity/Entity.h
Executable file
@@ -0,0 +1,226 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__Entity_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__Entity_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
class Level;
|
||||
class Player;
|
||||
class EntityPos;
|
||||
class Material;
|
||||
class ItemEntity;
|
||||
class ItemInstance;
|
||||
class CompoundTag;
|
||||
|
||||
#include "EntityRendererId.h"
|
||||
#include "../phys/AABB.h"
|
||||
#include "../../SharedConstants.h"
|
||||
//#include "../../util/MemUtils.h"
|
||||
#include "../../util/Mth.h"
|
||||
#include "../../util/Random.h"
|
||||
|
||||
class SynchedEntityData;
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
static int entityCounter;
|
||||
static const int TOTAL_AIR_SUPPLY = 15 * SharedConstants::TicksPerSecond;
|
||||
|
||||
Entity(Level* level);
|
||||
virtual ~Entity();
|
||||
|
||||
void _init();
|
||||
virtual void reset(); // { super::reset(); _init(); }
|
||||
|
||||
int hashCode();
|
||||
bool operator==(Entity& rhs);
|
||||
|
||||
virtual void setLevel(Level* level);
|
||||
|
||||
virtual void remove();
|
||||
|
||||
virtual void setPos(float x, float y, float z);
|
||||
virtual void move(float xa, float ya, float za);
|
||||
virtual void moveTo(float x, float y, float z, float yRot, float xRot);
|
||||
virtual void moveRelative(float xa, float za, float speed);
|
||||
|
||||
virtual void lerpTo(float x, float y, float z, float yRot, float xRot, int steps);
|
||||
virtual void lerpMotion(float xd, float yd, float zd);
|
||||
|
||||
virtual void turn(float xo, float yo);
|
||||
virtual void interpolateTurn(float xo, float yo);
|
||||
|
||||
virtual void tick();
|
||||
virtual void baseTick();
|
||||
|
||||
virtual bool intersects(float x0, float y0, float z0, float x1, float y1, float z1);
|
||||
virtual bool isFree(float xa, float ya, float za, float grow);
|
||||
virtual bool isFree(float xa, float ya, float za);
|
||||
virtual bool isInWall();
|
||||
virtual bool isInWater();
|
||||
virtual bool isInLava();
|
||||
virtual bool isUnderLiquid(const Material* material);
|
||||
|
||||
virtual void makeStuckInWeb();
|
||||
|
||||
virtual float getHeadHeight();
|
||||
virtual float getShadowHeightOffs();
|
||||
|
||||
virtual float getBrightness(float a);
|
||||
|
||||
float distanceTo(Entity* e);
|
||||
float distanceTo(float x2, float y2, float z2);
|
||||
float distanceToSqr(float x2, float y2, float z2);
|
||||
float distanceToSqr(Entity* e);
|
||||
|
||||
virtual bool interactPreventDefault();
|
||||
virtual bool interact(Player* player);
|
||||
virtual void playerTouch(Player* player);
|
||||
|
||||
virtual void push(Entity* e);
|
||||
virtual void push(float xa, float ya, float za);
|
||||
|
||||
virtual bool isPickable();
|
||||
virtual bool isPushable();
|
||||
virtual bool isShootable();
|
||||
|
||||
virtual bool isSneaking();
|
||||
|
||||
virtual bool isAlive();
|
||||
virtual bool isOnFire();
|
||||
|
||||
virtual bool isPlayer();
|
||||
virtual bool isCreativeModeAllowed();
|
||||
|
||||
virtual bool shouldRender(Vec3& c);
|
||||
virtual bool shouldRenderAtSqrDistance(float distance);
|
||||
|
||||
virtual bool hurt(Entity* source, int damage);
|
||||
virtual void animateHurt();
|
||||
|
||||
virtual void handleEntityEvent(char eventId) {}
|
||||
|
||||
virtual float getPickRadius();
|
||||
|
||||
virtual ItemEntity* spawnAtLocation(int resource, int count);
|
||||
virtual ItemEntity* spawnAtLocation(int resource, int count, float yOffs);
|
||||
// @attn: right now this means a pointer that spawnAtLocation takes ownership of
|
||||
virtual ItemEntity* spawnAtLocation(ItemInstance* itemInstance, float yOffs);
|
||||
|
||||
virtual void awardKillScore(Entity* victim, int score);
|
||||
|
||||
virtual void setEquippedSlot(int slot, int item, int auxValue);
|
||||
|
||||
virtual bool save(CompoundTag* entityTag);
|
||||
virtual void saveWithoutId(CompoundTag* entityTag);
|
||||
virtual bool load(CompoundTag* entityTag);
|
||||
virtual SynchedEntityData* getEntityData();
|
||||
virtual const SynchedEntityData* getEntityData() const;
|
||||
|
||||
__inline bool isEntityType(int type) { return getEntityTypeId() == type; }
|
||||
virtual int getEntityTypeId() const = 0;
|
||||
virtual int getCreatureBaseType() const { return 0; }
|
||||
virtual EntityRendererId queryEntityRenderer() { return ER_DEFAULT_RENDERER; }
|
||||
|
||||
virtual bool isMob() { return false; }
|
||||
// I hate myself
|
||||
virtual bool isItemEntity();
|
||||
// Me 2
|
||||
virtual bool isHangingEntity();
|
||||
|
||||
virtual int getAuxData();
|
||||
|
||||
protected:
|
||||
virtual void setRot(float yRot, float xRot);
|
||||
virtual void setSize(float w, float h);
|
||||
virtual void setPos(EntityPos* pos);
|
||||
virtual void resetPos(bool clearMore);
|
||||
virtual void outOfWorld();
|
||||
|
||||
virtual void checkFallDamage(float ya, bool onGround);
|
||||
virtual void causeFallDamage(float fallDamage2);
|
||||
virtual void markHurt();
|
||||
|
||||
virtual void burn(int dmg);
|
||||
virtual void lavaHurt();
|
||||
|
||||
virtual void readAdditionalSaveData(CompoundTag* tag) = 0;
|
||||
virtual void addAdditonalSaveData(CompoundTag* tag) = 0;
|
||||
|
||||
virtual void playStepSound( int xt, int yt, int zt, int t );
|
||||
public:
|
||||
float x, y, z;
|
||||
|
||||
int xChunk, yChunk, zChunk;
|
||||
|
||||
int entityId;
|
||||
|
||||
float viewScale;
|
||||
|
||||
Level* level;
|
||||
float xo, yo, zo;
|
||||
float xd, yd, zd;
|
||||
float yRot, xRot;
|
||||
float yRotO, xRotO;
|
||||
|
||||
AABB bb;
|
||||
|
||||
float heightOffset; // = 0 / 16.0f;
|
||||
|
||||
float bbWidth;
|
||||
float bbHeight;
|
||||
|
||||
float walkDistO;
|
||||
float walkDist;
|
||||
|
||||
float xOld, yOld, zOld;
|
||||
float ySlideOffset;
|
||||
float footSize;
|
||||
float pushthrough;
|
||||
|
||||
int tickCount;
|
||||
int invulnerableTime;
|
||||
int airSupply;
|
||||
int onFire;
|
||||
int flameTime;
|
||||
|
||||
EntityRendererId entityRendererId;
|
||||
|
||||
//Ref<Entity>* ref;
|
||||
|
||||
// bool hovered = false;
|
||||
|
||||
// std::string customTextureUrl;
|
||||
// std::string customTextureUrl2;
|
||||
// /*protected*/ bool fireImmune = false;
|
||||
|
||||
float fallDistance;
|
||||
bool blocksBuilding;
|
||||
bool inChunk;
|
||||
|
||||
bool onGround;
|
||||
bool horizontalCollision, verticalCollision;
|
||||
bool collision;
|
||||
bool hurtMarked;
|
||||
|
||||
bool slide;
|
||||
bool removed;
|
||||
bool noPhysics;
|
||||
bool canRemove;
|
||||
bool invisible;
|
||||
bool reallyRemoveIfPlayer;
|
||||
protected:
|
||||
static Random sharedRandom;
|
||||
int airCapacity;
|
||||
bool makeStepSound;
|
||||
bool wasInWater;
|
||||
bool fireImmune;
|
||||
|
||||
protected:
|
||||
bool firstTick;
|
||||
int nextStep;
|
||||
static const int DATA_AIR_SUPPLY_ID = 1;
|
||||
bool isStuckInWeb;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__Entity_H__*/
|
||||
23
src/world/entity/EntityEvent.h
Executable file
23
src/world/entity/EntityEvent.h
Executable file
@@ -0,0 +1,23 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__EntityEvent_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__EntityEvent_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
class EntityEvent {
|
||||
public:
|
||||
static const char JUMP = 1;
|
||||
static const char HURT = 2;
|
||||
static const char DEATH = 3;
|
||||
static const char START_ATTACKING = 4;
|
||||
static const char STOP_ATTACKING = 5;
|
||||
|
||||
static const char TAMING_FAILED = 6;
|
||||
static const char TAMING_SUCCEEDED = 7;
|
||||
static const char SHAKE_WETNESS = 8;
|
||||
|
||||
static const char USE_ITEM_COMPLETE = 9;
|
||||
|
||||
static const char EAT_GRASS = 10;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityEvent_H__*/
|
||||
57
src/world/entity/EntityFactory.cpp
Executable file
57
src/world/entity/EntityFactory.cpp
Executable file
@@ -0,0 +1,57 @@
|
||||
#include "EntityFactory.h"
|
||||
#include "MobFactory.h"
|
||||
#include "../../nbt/CompoundTag.h"
|
||||
|
||||
#include "item/PrimedTnt.h"
|
||||
#include "projectile/Arrow.h"
|
||||
#include "projectile/ThrownEgg.h"
|
||||
#include "projectile/Snowball.h"
|
||||
#include "Painting.h"
|
||||
#include "item/FallingTile.h"
|
||||
|
||||
Entity* EntityFactory::CreateEntity( int typeId, Level* level )
|
||||
{
|
||||
switch (typeId) {
|
||||
case EntityTypes::IdItemEntity: return new ItemEntity(level);
|
||||
case EntityTypes::IdFallingTile:return new FallingTile(level);
|
||||
case EntityTypes::IdPrimedTnt: return new PrimedTnt(level);
|
||||
case EntityTypes::IdArrow: return new Arrow(level);
|
||||
case EntityTypes::IdThrownEgg: return new ThrownEgg(level);
|
||||
case EntityTypes::IdSnowball: return new Snowball(level);
|
||||
case EntityTypes::IdPainting: return new Painting(level);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Entity* EntityFactory::loadEntity( CompoundTag* tag, Level* level )
|
||||
{
|
||||
if (!tag) return NULL;
|
||||
if (!tag->contains("id")) return NULL;
|
||||
int id = tag->getInt("id");
|
||||
|
||||
Entity* e = NULL;
|
||||
|
||||
if (id < 0) {
|
||||
LOGE("Negative ItemId: %d at MobFactory::loadEntity\n", id);
|
||||
} else if (id < 64) {
|
||||
e = MobFactory::CreateMob(id, level);
|
||||
} else {
|
||||
e = CreateEntity(id, level);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
e->load(tag);
|
||||
|
||||
// Add "fixes" here :p
|
||||
if (e->isItemEntity()) {
|
||||
const ItemInstance& item = ((ItemEntity*)e)->item;
|
||||
// Remove items out of range, and now invalid
|
||||
if(item.isNull() || item.id < 0 || item.id >= Item::MAX_ITEMS || !Item::items[item.id]) {
|
||||
delete e;
|
||||
e = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
15
src/world/entity/EntityFactory.h
Executable file
15
src/world/entity/EntityFactory.h
Executable file
@@ -0,0 +1,15 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__EntityFactory_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__EntityFactory_H__
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
class CompoundTag;
|
||||
|
||||
class EntityFactory
|
||||
{
|
||||
public:
|
||||
static Entity* CreateEntity(int typeId, Level* level);
|
||||
static Entity* loadEntity(CompoundTag* tag, Level* level);
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityFactory_H__*/
|
||||
84
src/world/entity/EntityPos.h
Executable file
84
src/world/entity/EntityPos.h
Executable file
@@ -0,0 +1,84 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__EntityPos_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__EntityPos_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include "Entity.h"
|
||||
|
||||
class EntityPos
|
||||
{
|
||||
public:
|
||||
float x, y, z;
|
||||
float yRot, xRot;
|
||||
bool rot;
|
||||
bool move;
|
||||
|
||||
EntityPos(float x, float y, float z, float yRot, float xRot)
|
||||
: rot(false),
|
||||
move(false)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
this->yRot = yRot;
|
||||
this->xRot = xRot;
|
||||
rot = true;
|
||||
move = true;
|
||||
}
|
||||
|
||||
EntityPos(float x, float y, float z)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->z = z;
|
||||
move = true;
|
||||
rot = false;
|
||||
}
|
||||
|
||||
EntityPos(float yRot, float xRot)
|
||||
{
|
||||
this->yRot = yRot;
|
||||
this->xRot = xRot;
|
||||
rot = true;
|
||||
move = false;
|
||||
}
|
||||
|
||||
// EntityPos lerp(Entity* e, float f)
|
||||
// {
|
||||
// float xd = e->x+(x-e->x)*f;
|
||||
// float yd = e->y+(y-e->y)*f;
|
||||
// float zd = e->z+(z-e->z)*f;
|
||||
//
|
||||
// float yrdd = yRot-e->yRot;
|
||||
// float xrdd = xRot-e->xRot;
|
||||
//
|
||||
// while (yrdd>=180) yrdd-=360;
|
||||
// while (yrdd<-180) yrdd+=360;
|
||||
// while (xrdd>=180) xrdd-=360;
|
||||
// while (xrdd<-180) xrdd+=360;
|
||||
//
|
||||
// float yrd = e->yRot+yrdd*f;
|
||||
// float xrd = e->xRot+xrdd*f;
|
||||
//
|
||||
// while (yrd>=180) yrd-=360;
|
||||
// while (yrd<-180) yrd+=360;
|
||||
// while (xrd>=180) xrd-=360;
|
||||
// while (xrd<-180) xrd+=360;
|
||||
//
|
||||
// if (rot && move)
|
||||
// {
|
||||
// return /*new*/ EntityPos(xd, yd, zd, yrd, xrd);
|
||||
// }
|
||||
// if (move)
|
||||
// {
|
||||
// return /*new*/ EntityPos(xd, yd, zd);
|
||||
// }
|
||||
// if (rot)
|
||||
// {
|
||||
// return /*new*/ EntityPos(yrd, xrd);
|
||||
// }
|
||||
// return NULL;
|
||||
// }
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityPos_H__*/
|
||||
28
src/world/entity/EntityRendererId.h
Executable file
28
src/world/entity/EntityRendererId.h
Executable file
@@ -0,0 +1,28 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__EntityRendererId_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__EntityRendererId_H__
|
||||
|
||||
enum EntityRendererId {
|
||||
ER_DEFAULT_RENDERER,
|
||||
ER_QUERY_RENDERER,
|
||||
ER_TNT_RENDERER,
|
||||
ER_HUMANOID_RENDERER,
|
||||
ER_ITEM_RENDERER,
|
||||
ER_TRIPODCAMERA_RENDERER,
|
||||
ER_CHICKEN_RENDERER,
|
||||
ER_COW_RENDERER,
|
||||
ER_PIG_RENDERER,
|
||||
ER_SHEEP_RENDERER,
|
||||
ER_SHEEP_FUR_RENDERER,
|
||||
ER_ZOMBIE_RENDERER,
|
||||
ER_SKELETON_RENDERER,
|
||||
ER_SPIDER_RENDERER,
|
||||
ER_CREEPER_RENDERER,
|
||||
ER_ARROW_RENDERER,
|
||||
ER_PLAYER_RENDERER,
|
||||
ER_THROWNEGG_RENDERER,
|
||||
ER_SNOWBALL_RENDERER,
|
||||
ER_PAINTING_RENDERER,
|
||||
ER_FALLINGTILE_RENDERER
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityRendererId_H__*/
|
||||
129
src/world/entity/EntityTypes.h
Executable file
129
src/world/entity/EntityTypes.h
Executable file
@@ -0,0 +1,129 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__EntityTypes_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__EntityTypes_H__
|
||||
|
||||
#include "../../util/Mth.h"
|
||||
|
||||
//? 3 bits ?
|
||||
class BaseTypes {
|
||||
public:
|
||||
static const int Entity = 1;
|
||||
static const int Item = 2;
|
||||
};
|
||||
|
||||
//? 4 bits ?
|
||||
class EntityTypes {
|
||||
public:
|
||||
/*
|
||||
static const int Mob = 1;
|
||||
static const int Particle = 2;
|
||||
static const int ItemEntity = 3;
|
||||
*/
|
||||
|
||||
// Forgive me, but I'm not sure I have time to finish my RTTI
|
||||
// implementation -> this. Mobs up to 63, rest on top of that
|
||||
static const int IdItemEntity = 64;
|
||||
|
||||
static const int IdPrimedTnt = 65;
|
||||
static const int IdFallingTile = 66;
|
||||
|
||||
static const int IdArrow = 80;
|
||||
static const int IdSnowball = 81;
|
||||
static const int IdThrownEgg= 82;
|
||||
static const int IdPainting = 83;
|
||||
};
|
||||
|
||||
// For now; mobs 0-63
|
||||
// Those constants are unfortunately the same "type" as EntityTypes
|
||||
// @todo: fix something nicer (but keep the IDs)
|
||||
class MobTypes {
|
||||
public:
|
||||
static const int BaseEnemy = 1;
|
||||
static const int BaseCreature = 2;
|
||||
static const int BaseWaterCreature = 3;
|
||||
|
||||
static const int Chicken = 10;
|
||||
static const int Cow = 11;
|
||||
static const int Pig = 12;
|
||||
static const int Sheep = 13;
|
||||
|
||||
static const int Zombie = 32;
|
||||
static const int Creeper = 33;
|
||||
static const int Skeleton = 34;
|
||||
static const int Spider = 35;
|
||||
static const int PigZombie = 36;
|
||||
};
|
||||
|
||||
struct ParticleType {
|
||||
enum Id {
|
||||
none,
|
||||
bubble,
|
||||
crit,
|
||||
smoke,
|
||||
explode,
|
||||
flame,
|
||||
lava,
|
||||
largesmoke,
|
||||
reddust,
|
||||
iconcrack,
|
||||
snowballpoof,
|
||||
largeexplode,
|
||||
hugeexplosion
|
||||
};
|
||||
};
|
||||
|
||||
#define PARTICLETYPE(x) (ParticleType::x,#x)
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
/*
|
||||
class ClassTree {
|
||||
public:
|
||||
static bool isEntityType(int type, int entityType) {
|
||||
return getBaseType(type) == BaseTypes::Entity? getSubType(1, type) == entityType : false;
|
||||
}
|
||||
static bool isBaseType(int type, int baseType) {
|
||||
return getBaseType(type) == getBaseType(baseType);
|
||||
}
|
||||
static int getBaseType(int type) {
|
||||
return getSubType(0, type);
|
||||
}
|
||||
static int getSubType(int subTypeIndex, int type) {
|
||||
return type & (0xff << (subTypeIndex << 3));
|
||||
}
|
||||
static bool isSameTypeUpTo(int a, int b, int hierarchy) {
|
||||
if (hierarchy < 0) hierarchy = Mth::Min(getHierarchyLevel(a), getHierarchyLevel(b));
|
||||
for (int i = 0; i <= hierarchy; ++i)
|
||||
if (getSubType(i, a) != getSubType(i, b)) return false;
|
||||
return true;
|
||||
}
|
||||
static int getHierarchyLevel(int type) {
|
||||
if (type & 0xff) {
|
||||
if (type & 0xff00) {
|
||||
if (type & 0xff0000) {
|
||||
if (type & 0xff000000) return 3;
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int createBaseType(int type) {
|
||||
return _create(type);
|
||||
}
|
||||
static int createEntityType(int type) {
|
||||
return _create(BaseTypes::Entity, type);
|
||||
}
|
||||
static int createMobType(int type) {
|
||||
return _create(BaseTypes::Entity, EntityTypes::Mob, type);
|
||||
}
|
||||
static int _create(int base, int a = 0, int b = 0, int c = 0) {
|
||||
return base | (a << 8) | (b << 16) | (c << 24);
|
||||
}
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityTypes_H__*/
|
||||
71
src/world/entity/FlyingMob.cpp
Executable file
71
src/world/entity/FlyingMob.cpp
Executable file
@@ -0,0 +1,71 @@
|
||||
#include "FlyingMob.h"
|
||||
#include "../level/Level.h"
|
||||
#include "../level/tile/Tile.h"
|
||||
#include "../../util/Mth.h"
|
||||
|
||||
|
||||
FlyingMob::FlyingMob( Level* level )
|
||||
: super(level)
|
||||
{
|
||||
}
|
||||
|
||||
void FlyingMob::travel( float xa, float ya )
|
||||
{
|
||||
if (isInWater()) {
|
||||
moveRelative(xa, ya, 0.02f);
|
||||
move(xd, yd, zd);
|
||||
|
||||
xd *= 0.80f;
|
||||
yd *= 0.80f;
|
||||
zd *= 0.80f;
|
||||
} else if (isInLava()) {
|
||||
moveRelative(xa, ya, 0.02f);
|
||||
move(xd, yd, zd);
|
||||
xd *= 0.50f;
|
||||
yd *= 0.50f;
|
||||
zd *= 0.50f;
|
||||
} else {
|
||||
float friction = 0.91f;
|
||||
if (onGround) {
|
||||
friction = 0.6f * 0.91f;
|
||||
int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z));
|
||||
if (t > 0) {
|
||||
friction = Tile::tiles[t]->friction * 0.91f;
|
||||
}
|
||||
}
|
||||
|
||||
float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction);
|
||||
moveRelative(xa, ya, (onGround ? 0.1f * friction2 : 0.02f));
|
||||
|
||||
friction = 0.91f;
|
||||
if (onGround) {
|
||||
friction = 0.6f * 0.91f;
|
||||
int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z));
|
||||
if (t > 0) {
|
||||
friction = Tile::tiles[t]->friction * 0.91f;
|
||||
}
|
||||
}
|
||||
|
||||
move(xd, yd, zd);
|
||||
|
||||
xd *= friction;
|
||||
yd *= friction;
|
||||
zd *= friction;
|
||||
}
|
||||
walkAnimSpeedO = walkAnimSpeed;
|
||||
float xxd = x - xo;
|
||||
float zzd = z - zo;
|
||||
float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4;
|
||||
if (wst > 1) wst = 1;
|
||||
walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f;
|
||||
walkAnimPos += walkAnimSpeed;
|
||||
}
|
||||
|
||||
bool FlyingMob::onLadder()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void FlyingMob::causeFallDamage( float distance )
|
||||
{
|
||||
}
|
||||
24
src/world/entity/FlyingMob.h
Executable file
24
src/world/entity/FlyingMob.h
Executable file
@@ -0,0 +1,24 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__FlyingMob_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__FlyingMob_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include "Mob.h"
|
||||
|
||||
class Level;
|
||||
|
||||
|
||||
class FlyingMob: public Mob
|
||||
{
|
||||
typedef Mob super;
|
||||
public:
|
||||
FlyingMob(Level* level);
|
||||
|
||||
void travel(float xa, float ya);
|
||||
|
||||
bool onLadder();
|
||||
protected:
|
||||
void causeFallDamage(float distance);
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__FlyingMob_H__*/
|
||||
234
src/world/entity/HangingEntity.cpp
Executable file
234
src/world/entity/HangingEntity.cpp
Executable file
@@ -0,0 +1,234 @@
|
||||
#include "HangingEntity.h"
|
||||
#include "../Direction.h"
|
||||
#include "../level/Level.h"
|
||||
#include "../level/material/Material.h"
|
||||
HangingEntity::HangingEntity( Level* level )
|
||||
: super(level) {
|
||||
init();
|
||||
}
|
||||
|
||||
HangingEntity::HangingEntity( Level* level, int xTile, int yTile, int zTile, int dir )
|
||||
: super(level), xTile(xTile), yTile(yTile), zTile(zTile) {
|
||||
init();
|
||||
}
|
||||
void HangingEntity::setPosition( int x, int y, int z ) {
|
||||
xTile = x;
|
||||
yTile = y;
|
||||
zTile = z;
|
||||
}
|
||||
void HangingEntity::init() {
|
||||
heightOffset = 0;
|
||||
setSize(0.5f, 0.5f);
|
||||
dir = 0;
|
||||
checkInterval = 0;
|
||||
}
|
||||
|
||||
void HangingEntity::setDir( int dir ) {
|
||||
//printf("HangingEntity dir: %d\n", dir);
|
||||
this->dir = dir;
|
||||
yRotO = yRot = float(dir * 90);
|
||||
|
||||
float w = float(getWidth());
|
||||
float h = float(getHeight());
|
||||
float d = float(getWidth());
|
||||
|
||||
if (dir == Direction::NORTH || dir == Direction::SOUTH) {
|
||||
d = 2.0f;
|
||||
yRot = yRotO = float(Direction::DIRECTION_OPPOSITE[dir] * 90);
|
||||
} else {
|
||||
w = 2.0f;
|
||||
}
|
||||
|
||||
w /= 32.0f;
|
||||
h /= 32.0f;
|
||||
d /= 32.0f;
|
||||
|
||||
float x = xTile + 0.5f;
|
||||
float y = yTile + 0.5f;
|
||||
float z = zTile + 0.5f;
|
||||
|
||||
float offset = 0.5f + 1.0f / 16.0f;
|
||||
|
||||
if (dir == Direction::NORTH) z -= offset;
|
||||
if (dir == Direction::WEST) x -= offset;
|
||||
if (dir == Direction::SOUTH) z += offset;
|
||||
if (dir == Direction::EAST) x += offset;
|
||||
|
||||
if (dir == Direction::NORTH) x -= offs(getWidth());
|
||||
if (dir == Direction::WEST) z += offs(getWidth());
|
||||
if (dir == Direction::SOUTH) x += offs(getWidth());
|
||||
if (dir == Direction::EAST) z -= offs(getWidth());
|
||||
y += offs(getHeight());
|
||||
|
||||
setPos(x, y, z);
|
||||
|
||||
float ss = -(0.5f / 16.0f);
|
||||
bb.set(x - w - ss, y - h - ss, z - d - ss, x + w + ss, y + h + ss, z + d + ss);
|
||||
}
|
||||
float HangingEntity::offs( int w ) {
|
||||
if(w == 32) return 0.5f;
|
||||
if(w == 64) return 0.5f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HangingEntity::tick() {
|
||||
if(checkInterval++ == 20 * 5 && !level->isClientSide) {
|
||||
checkInterval = 0;
|
||||
if(!removed && !survives()) {
|
||||
remove();
|
||||
dropItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HangingEntity::survives() {
|
||||
if (!level->getCubes(this, bb).empty()) {
|
||||
return false;
|
||||
} else {
|
||||
int ws = Mth::Max(1, getWidth() / 16);
|
||||
int hs = Mth::Max(1, getHeight() / 16);
|
||||
|
||||
int xt = xTile;
|
||||
int yt = yTile;
|
||||
int zt = zTile;
|
||||
if (dir == Direction::NORTH) xt = Mth::floor(x - getWidth() / 32.0f);
|
||||
if (dir == Direction::WEST) zt = Mth::floor(z - getWidth() / 32.0f);
|
||||
if (dir == Direction::SOUTH) xt = Mth::floor(x - getWidth() / 32.0f);
|
||||
if (dir == Direction::EAST) zt = Mth::floor(z - getWidth() / 32.0f);
|
||||
yt = Mth::floor(y - getHeight() / 32.0f);
|
||||
|
||||
for (int ss = 0; ss < ws; ++ss) {
|
||||
for (int yy = 0; yy < hs; ++yy) {
|
||||
const Material* m;
|
||||
if (dir == Direction::NORTH || dir == Direction::SOUTH) {
|
||||
m = level->getMaterial(xt + ss, yt + yy, zTile);
|
||||
} else {
|
||||
m = level->getMaterial(xTile, yt + yy, zt + ss);
|
||||
}
|
||||
if (!m->isSolid())
|
||||
return false;
|
||||
}
|
||||
EntityList entities = level->getEntities(this, bb);
|
||||
for(EntityList::iterator ei = entities.begin(); ei != entities.end(); ++ei) {
|
||||
Entity* entity = *(ei);
|
||||
if(entity->isHangingEntity())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HangingEntity::isHangingEntity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HangingEntity::isPickable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HangingEntity::interact(Player* player) {
|
||||
if(!removed && !level->isClientSide) {
|
||||
if(player != NULL
|
||||
&& player->inventory != NULL
|
||||
&& player->inventory->getSelected() != NULL
|
||||
&& player->inventory->getSelected()->id == Item::bow->id)
|
||||
return false;
|
||||
remove();
|
||||
markHurt();
|
||||
if(player != NULL && !player->abilities.instabuild)
|
||||
dropItem();
|
||||
return true;
|
||||
} else {
|
||||
return !removed;
|
||||
}
|
||||
}
|
||||
|
||||
void HangingEntity::move( float xa, float ya, float za ) {
|
||||
if(!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) {
|
||||
dropItem();
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
void HangingEntity::push( float xa, float ya, float za ) {
|
||||
if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) {
|
||||
dropItem();
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
void HangingEntity::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
tag->putByte("Direction", (char) dir);
|
||||
tag->putInt("TileX", xTile);
|
||||
tag->putInt("TileY", yTile);
|
||||
tag->putInt("TileZ", zTile);
|
||||
|
||||
// Back compat
|
||||
switch (dir) {
|
||||
case Direction::NORTH:
|
||||
tag->putByte("Dir", char(0));
|
||||
break;
|
||||
case Direction::WEST:
|
||||
tag->putByte("Dir", char(1));
|
||||
break;
|
||||
case Direction::SOUTH:
|
||||
tag->putByte("Dir", char(2));
|
||||
break;
|
||||
case Direction::EAST:
|
||||
tag->putByte("Dir", char(3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HangingEntity::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
if (tag->contains("Direction")) {
|
||||
dir = tag->getByte("Direction");
|
||||
} else {
|
||||
switch (tag->getByte("Dir")) {
|
||||
case 0:
|
||||
dir = Direction::NORTH;
|
||||
break;
|
||||
case 1:
|
||||
dir = Direction::WEST;
|
||||
break;
|
||||
case 2:
|
||||
dir = Direction::SOUTH;
|
||||
break;
|
||||
case 3:
|
||||
dir = Direction::EAST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xTile = tag->getInt("TileX");
|
||||
yTile = tag->getInt("TileY");
|
||||
zTile = tag->getInt("TileZ");
|
||||
setDir(dir);
|
||||
}
|
||||
|
||||
float HangingEntity::getBrightness( float a ) {
|
||||
int xTile = Mth::floor(x);
|
||||
int zTile = Mth::floor(z);
|
||||
//if (dir == Direction::NORTH) xTile--;
|
||||
//if (dir == Direction::WEST) zTile++;
|
||||
//if (dir == Direction::SOUTH) xTile++;
|
||||
//if (dir == Direction::EAST) zTile--;
|
||||
if (level->hasChunkAt(xTile, 0, zTile)) {
|
||||
int yTile = Mth::floor(y);
|
||||
return level->getBrightness(xTile, yTile, zTile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HangingEntity::hurt( Entity* source, int damage ) {
|
||||
if(!removed && !level->isClientSide) {
|
||||
remove();
|
||||
markHurt();
|
||||
Player* player = Player::asPlayer(source);
|
||||
if(player != NULL && player->abilities.instabuild) {
|
||||
return true;
|
||||
}
|
||||
dropItem();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
36
src/world/entity/HangingEntity.h
Executable file
36
src/world/entity/HangingEntity.h
Executable file
@@ -0,0 +1,36 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__HangingEntity_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__HangingEntity_H__
|
||||
|
||||
#include "Entity.h"
|
||||
class HangingEntity : public Entity {
|
||||
typedef Entity super;
|
||||
public:
|
||||
HangingEntity(Level* level);
|
||||
HangingEntity(Level* level, int xTile, int yTile, int zTile, int dir);
|
||||
void init();
|
||||
void setDir(int dir);
|
||||
void setPosition(int x, int y, int z);
|
||||
virtual void tick();
|
||||
virtual bool survives();
|
||||
bool isPickable();
|
||||
bool interact(Player* player);
|
||||
void move(float xa, float ya, float za);
|
||||
void push(float xa, float ya, float za);
|
||||
virtual void addAdditonalSaveData(CompoundTag* tag);
|
||||
virtual void readAdditionalSaveData(CompoundTag* tag);
|
||||
virtual int getWidth() = 0;
|
||||
virtual int getHeight() = 0;
|
||||
virtual void dropItem() = 0;
|
||||
virtual bool isHangingEntity();
|
||||
virtual float getBrightness(float a);
|
||||
virtual bool hurt(Entity* source, int damage);
|
||||
private:
|
||||
float offs(int w);
|
||||
public:
|
||||
int dir;
|
||||
int xTile, yTile, zTile;
|
||||
private:
|
||||
int checkInterval;
|
||||
};
|
||||
|
||||
#endif /* NET_MINECRAFT_WORLD_ENTITY__HangingEntity_H__ */
|
||||
1144
src/world/entity/Mob.cpp
Executable file
1144
src/world/entity/Mob.cpp
Executable file
File diff suppressed because it is too large
Load Diff
249
src/world/entity/Mob.h
Executable file
249
src/world/entity/Mob.h
Executable file
@@ -0,0 +1,249 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__Mob_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__Mob_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include <string>
|
||||
#include "Entity.h"
|
||||
#include "EntityTypes.h"
|
||||
#include "SynchedEntityData.h"
|
||||
|
||||
|
||||
class CompoundTag;
|
||||
|
||||
class Level;
|
||||
class CompundTag;
|
||||
|
||||
class MoveControl;
|
||||
class JumpControl;
|
||||
class PathNavigation;
|
||||
class GoalSelector;
|
||||
class Sensing;
|
||||
|
||||
class Mob: public Entity
|
||||
{
|
||||
typedef Entity super;
|
||||
public:
|
||||
static const int ATTACK_DURATION = 5;
|
||||
static const int SWING_DURATION = 8;
|
||||
|
||||
Mob(Level* level);
|
||||
virtual ~Mob();
|
||||
|
||||
void _init();
|
||||
virtual void reset();
|
||||
|
||||
virtual void knockback(Entity* source, int dmg, float xd, float zd);
|
||||
virtual void die(Entity* source);
|
||||
|
||||
virtual bool canSee(Entity* target);
|
||||
|
||||
virtual bool onLadder();
|
||||
|
||||
virtual void spawnAnim();
|
||||
virtual std::string getTexture();
|
||||
|
||||
virtual bool isAlive();
|
||||
virtual bool isPickable();
|
||||
virtual bool isPushable();
|
||||
virtual bool isShootable();
|
||||
|
||||
MoveControl* getMoveControl();
|
||||
JumpControl* getJumpControl();
|
||||
|
||||
virtual bool isSleeping();
|
||||
virtual bool isWaterMob();
|
||||
|
||||
virtual bool isSneaking();
|
||||
virtual void setSneaking(bool value);
|
||||
|
||||
virtual float getHeadHeight();
|
||||
|
||||
virtual float getVoicePitch();
|
||||
|
||||
virtual void playAmbientSound();
|
||||
virtual int getAmbientSoundInterval();
|
||||
virtual int getItemInHandIcon(ItemInstance* item, int layer) {
|
||||
return item->getIcon();
|
||||
}
|
||||
virtual void lerpTo(float x, float y, float z, float yRot, float xRot, int steps);
|
||||
|
||||
void setYya( float yya );
|
||||
float getSpeed();
|
||||
void setSpeed(float speed);
|
||||
void setJumping(bool jump);
|
||||
|
||||
virtual void tick();
|
||||
virtual void baseTick();
|
||||
virtual void superTick();
|
||||
|
||||
virtual void heal(int heal);
|
||||
virtual int getMaxHealth() { return 10; }
|
||||
virtual bool hurt(Entity* source, int dmg);
|
||||
virtual void actuallyHurt(int dmg);
|
||||
virtual void animateHurt();
|
||||
virtual int getArmorValue();
|
||||
|
||||
virtual HitResult pick(float range, float a);
|
||||
|
||||
virtual void travel(float xa, float ya);
|
||||
virtual void updateWalkAnim();
|
||||
|
||||
virtual void aiStep();
|
||||
|
||||
virtual SynchedEntityData* getEntityData();
|
||||
virtual const SynchedEntityData* getEntityData() const;
|
||||
|
||||
virtual void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
virtual void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
virtual void lookAt(Entity* e, float yMax, float xMax);
|
||||
virtual bool isLookingAtAnEntity();
|
||||
//virtual Entity* getLookingAt();
|
||||
|
||||
virtual void beforeRemove();
|
||||
|
||||
virtual bool canSpawn();
|
||||
|
||||
virtual float getAttackAnim(float a);
|
||||
|
||||
virtual Vec3 getPos(float a);
|
||||
virtual Vec3 getLookAngle();
|
||||
virtual Vec3 getViewVector(float a);
|
||||
|
||||
virtual int getMaxSpawnClusterSize();
|
||||
|
||||
virtual bool isMob() { return true; }
|
||||
virtual bool isBaby() { return false; }
|
||||
|
||||
virtual void handleEntityEvent(char id);
|
||||
virtual ItemInstance* getCarriedItem() {return NULL;}
|
||||
virtual int getUseItemDuration() {return 0;}
|
||||
virtual void swing();
|
||||
protected:
|
||||
virtual void causeFallDamage(float distance);
|
||||
|
||||
virtual void outOfWorld();
|
||||
virtual bool removeWhenFarAway();
|
||||
|
||||
virtual int getDeathLoot();
|
||||
virtual void dropDeathLoot();
|
||||
|
||||
virtual bool isImmobile();
|
||||
|
||||
virtual void jumpFromGround();
|
||||
|
||||
virtual void updateAi();
|
||||
virtual void newServerAiStep();
|
||||
|
||||
virtual void setSize(float w, float h);
|
||||
|
||||
virtual int getMaxHeadXRot();
|
||||
|
||||
virtual float getSoundVolume();
|
||||
virtual const char* getAmbientSound();
|
||||
virtual std::string getHurtSound();
|
||||
virtual std::string getDeathSound();
|
||||
|
||||
virtual float getWalkingSpeedModifier();
|
||||
|
||||
virtual int getDamageAfterArmorAbsorb(int damage);
|
||||
virtual void hurtArmor(int damage);
|
||||
|
||||
bool interpolateOnly();
|
||||
virtual bool useNewAi();
|
||||
bool getSharedFlag(int flag);
|
||||
void setSharedFlag(int flag, bool value);
|
||||
void checkDespawn(Mob* nearestBlocking);
|
||||
void checkDespawn();
|
||||
void updateAttackAnim();
|
||||
private:
|
||||
float rotlerp(float a, float b, float max);
|
||||
public:
|
||||
int invulnerableDuration;
|
||||
|
||||
float timeOffs;
|
||||
|
||||
float rotA;
|
||||
float yBodyRot, yBodyRotO;
|
||||
//bool interpolateOnly;
|
||||
|
||||
float oAttackAnim, attackAnim;
|
||||
|
||||
int health;
|
||||
int lastHealth;
|
||||
|
||||
int hurtTime;
|
||||
int hurtDuration;
|
||||
float hurtDir;
|
||||
|
||||
int deathTime;
|
||||
int attackTime;
|
||||
float oTilt, tilt;
|
||||
|
||||
int lookTime;
|
||||
float fallTime;
|
||||
|
||||
float walkAnimSpeedO;
|
||||
float walkAnimSpeed;
|
||||
float walkAnimPos;
|
||||
|
||||
Vec3 aimDirection;
|
||||
int arrowCount;
|
||||
int removeArrowTime;
|
||||
|
||||
Random random;
|
||||
Sensing* sensing;
|
||||
|
||||
//@note: This is a temporary fix for DamageSource that bypasses armor
|
||||
// or creating two functions, that does virtually the same
|
||||
// except one bypasses armor. It's enough virtual calls and chains
|
||||
// of super-calls for me to think this is safer.
|
||||
bool bypassArmor;
|
||||
protected:
|
||||
SynchedEntityData entityData;
|
||||
bool swinging;
|
||||
int swingTime;
|
||||
int noActionTime;
|
||||
float xxa, yya, yRotA;
|
||||
float defaultLookAngle;
|
||||
|
||||
float runSpeed;
|
||||
float walkingSpeed;
|
||||
float flyingSpeed;
|
||||
|
||||
std::string textureName;
|
||||
std::string modelName;
|
||||
int deathScore;
|
||||
float oRun, run;
|
||||
float animStep, animStepO;
|
||||
float rotOffs;
|
||||
float bobStrength;
|
||||
float renderOffset;
|
||||
|
||||
int lSteps;
|
||||
float lx, ly, lz, lyr, lxr;
|
||||
int lastHurt;
|
||||
int dmgSpill;
|
||||
|
||||
float sentX, sentY, sentZ, sentRotX, sentRotY;
|
||||
float sentXd, sentYd, sentZd;
|
||||
|
||||
//bool hasHair;
|
||||
bool allowAlpha;
|
||||
bool jumping;
|
||||
bool autoSendPosRot;
|
||||
|
||||
MoveControl* moveControl;
|
||||
JumpControl* jumpControl;
|
||||
PathNavigation* navigation;
|
||||
GoalSelector* goalSelector;
|
||||
GoalSelector* targetSelector;
|
||||
private:
|
||||
int lookingAtId;
|
||||
int ambientSoundTime;
|
||||
|
||||
float speed;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__Mob_H__*/
|
||||
50
src/world/entity/MobCategory.cpp
Executable file
50
src/world/entity/MobCategory.cpp
Executable file
@@ -0,0 +1,50 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__
|
||||
|
||||
#include "EntityTypes.h"
|
||||
#include "MobCategory.h"
|
||||
#include "../level/material/Material.h"
|
||||
|
||||
|
||||
const MobCategory MobCategory::monster(
|
||||
MobTypes::BaseEnemy,
|
||||
10,
|
||||
20,
|
||||
false);
|
||||
|
||||
//
|
||||
|
||||
const MobCategory MobCategory::creature(
|
||||
MobTypes::BaseCreature,
|
||||
10,
|
||||
15,
|
||||
true);
|
||||
|
||||
//
|
||||
|
||||
const MobCategory MobCategory::waterCreature(
|
||||
MobTypes::BaseWaterCreature,
|
||||
5,
|
||||
10,
|
||||
true);
|
||||
|
||||
//
|
||||
// Init an array with all defined MobCategory'ies
|
||||
//
|
||||
const MobCategory* const MobCategory::values[] = {
|
||||
&MobCategory::monster,
|
||||
&MobCategory::creature,
|
||||
&MobCategory::waterCreature
|
||||
};
|
||||
|
||||
/*static*/
|
||||
void MobCategory::initMobCategories() {
|
||||
monster.setMaterial(Material::air);
|
||||
creature.setMaterial(Material::air);
|
||||
waterCreature.setMaterial(Material::water);
|
||||
}
|
||||
|
||||
|
||||
const int MobCategory::numValues = sizeof(values) / sizeof(values[0]);
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__*/
|
||||
60
src/world/entity/MobCategory.h
Executable file
60
src/world/entity/MobCategory.h
Executable file
@@ -0,0 +1,60 @@
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include "../../platform/log.h"
|
||||
|
||||
class Material;
|
||||
|
||||
class MobCategory
|
||||
{
|
||||
public:
|
||||
static void initMobCategories();
|
||||
|
||||
//
|
||||
static const MobCategory monster;
|
||||
static const MobCategory creature;
|
||||
static const MobCategory waterCreature;
|
||||
//@todo: rewrite to std::vector with [] init
|
||||
static const MobCategory* const values[];
|
||||
static const int numValues;
|
||||
|
||||
int getBaseClassId() const {
|
||||
return _baseClassId;
|
||||
}
|
||||
|
||||
int getMaxInstancesPerChunk() const {
|
||||
return _max;
|
||||
}
|
||||
|
||||
int getMaxInstancesPerLevel() const {
|
||||
return _maxPerLevel;
|
||||
}
|
||||
|
||||
const Material* getSpawnPositionMaterial() const {
|
||||
return _spawnPositionMaterial;
|
||||
}
|
||||
|
||||
bool isFriendly() const {
|
||||
return _isFriendly;
|
||||
}
|
||||
|
||||
private:
|
||||
const int _baseClassId;
|
||||
const int _max;
|
||||
const int _maxPerLevel;
|
||||
mutable const Material* _spawnPositionMaterial;
|
||||
const bool _isFriendly;
|
||||
|
||||
MobCategory(int baseClassId, int max, int maxPerLevel, bool isFriendly)
|
||||
: _baseClassId(baseClassId),
|
||||
_max(max),
|
||||
_maxPerLevel(maxPerLevel),
|
||||
_spawnPositionMaterial(NULL),
|
||||
_isFriendly(isFriendly)
|
||||
{
|
||||
//LOGI("Creating a Mobcategory: %d, %d, %p, %d ", _baseClassId, _max, _spawnPositionMaterial, _isFriendly);
|
||||
}
|
||||
|
||||
void setMaterial(const Material* material) const {
|
||||
_spawnPositionMaterial = material;
|
||||
}
|
||||
};
|
||||
90
src/world/entity/MobFactory.h
Executable file
90
src/world/entity/MobFactory.h
Executable file
@@ -0,0 +1,90 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__MobFactory_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__MobFactory_H__
|
||||
|
||||
#include "EntityTypes.h"
|
||||
#include "animal/AnimalInclude.h"
|
||||
#include "monster/MonsterInclude.h"
|
||||
|
||||
class MobFactory {
|
||||
public:
|
||||
static Mob* CreateMob(int mobType, Level* level) {
|
||||
//LOGI("Trying to create a mob with type: %d!\n", mobType);
|
||||
|
||||
Mob* mob = NULL;
|
||||
switch(mobType) {
|
||||
// Animals
|
||||
case MobTypes::Chicken:
|
||||
mob = new Chicken(level);
|
||||
break;
|
||||
case MobTypes::Cow:
|
||||
mob = new Cow(level);
|
||||
break;
|
||||
case MobTypes::Pig:
|
||||
mob = new Pig(level);
|
||||
break;
|
||||
case MobTypes::Sheep:
|
||||
mob = new Sheep(level);
|
||||
break;
|
||||
|
||||
// Monsters
|
||||
case MobTypes::Creeper:
|
||||
mob = new Creeper(level);
|
||||
break;
|
||||
case MobTypes::Zombie:
|
||||
mob = new Zombie(level);
|
||||
break;
|
||||
case MobTypes::Skeleton:
|
||||
mob = new Skeleton(level);
|
||||
break;
|
||||
case MobTypes::Spider:
|
||||
mob = new Spider(level);
|
||||
break;
|
||||
case MobTypes::PigZombie:
|
||||
mob = new PigZombie(level);
|
||||
break;
|
||||
default:
|
||||
LOGE("Unknown mob type requested: %d\n", mobType);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mob) {
|
||||
mob->health = mob->getMaxHealth();
|
||||
}
|
||||
return mob;
|
||||
}
|
||||
|
||||
static void clearStaticTestMobs() {
|
||||
getStaticTestMob(0, NULL);
|
||||
}
|
||||
|
||||
// @huge @attn: Those needs to be cleared for every new level
|
||||
static Mob* getStaticTestMob(int mobType, Level* level) {
|
||||
static std::map<int, Mob*> _mobs;
|
||||
static Level* lastLevel = NULL;
|
||||
|
||||
bool wantClear = (mobType == 0) && (level == NULL);
|
||||
bool newLevel = (level != lastLevel);
|
||||
lastLevel = level;
|
||||
|
||||
// We either want to clear all mobs, or a new level is created
|
||||
if (wantClear || newLevel) {
|
||||
for (std::map<int, Mob*>::iterator it = _mobs.begin(); it != _mobs.end(); ++it)
|
||||
delete it->second;
|
||||
_mobs.clear();
|
||||
|
||||
if (wantClear) return NULL;
|
||||
}
|
||||
|
||||
std::map<int, Mob*>::iterator it = _mobs.find(mobType);
|
||||
|
||||
if (it != _mobs.end())
|
||||
return it->second;
|
||||
|
||||
// Didn't exist, add it
|
||||
Mob* mob = CreateMob(mobType, level);
|
||||
_mobs.insert(std::make_pair(mobType, mob));
|
||||
return mob;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__MobFactory_H__*/
|
||||
84
src/world/entity/Motive.cpp
Executable file
84
src/world/entity/Motive.cpp
Executable file
@@ -0,0 +1,84 @@
|
||||
#include "Motive.h"
|
||||
const Motive Motive::Kebab("Kebab", 16, 16, 0 * 16, 0 * 16);
|
||||
const Motive Motive::Aztec("Aztec", 16, 16, 1 * 16, 0 * 16);
|
||||
const Motive Motive::Alban("Alban", 16, 16, 2 * 16, 0 * 16);
|
||||
const Motive Motive::Aztec2("Aztec2", 16, 16, 3 * 16, 0 * 16);
|
||||
const Motive Motive::Bomb("Bomb", 16, 16, 4 * 16, 0 * 16);
|
||||
const Motive Motive::Plant("Plant", 16, 16, 5 * 16, 0 * 16);
|
||||
const Motive Motive::Wasteland("Wasteland", 16, 16, 6 * 16, 0 * 16);
|
||||
const Motive Motive::Pool("Pool", 32, 16, 0 * 16, 2 * 16);
|
||||
const Motive Motive::Courbet("Courbet", 32, 16, 2 * 16, 2 * 16);
|
||||
const Motive Motive::Sea("Sea", 32, 16, 4 * 16, 2 * 16);
|
||||
const Motive Motive::Sunset("Sunset", 32, 16, 6 * 16, 2 * 16);
|
||||
const Motive Motive::Creebet("Creebet", 32, 16, 8 * 16, 2 * 16);
|
||||
const Motive Motive::Wanderer("Wanderer", 16, 32, 0 * 16, 4 * 16);
|
||||
const Motive Motive::Graham("Graham", 16, 32, 1 * 16, 4 * 16);
|
||||
const Motive Motive::Match("Match", 32, 32, 0 * 16, 8 * 16);
|
||||
const Motive Motive::Bust("Bust", 32, 32, 2 * 16, 8 * 16);
|
||||
const Motive Motive::Stage("Stage", 32, 32, 4 * 16, 8 * 16);
|
||||
const Motive Motive::Void("Void", 32, 32, 6 * 16, 8 * 16);
|
||||
const Motive Motive::SkullAndRoses("SkullAndRoses", 32, 32, 8 * 16, 8 * 16);
|
||||
const Motive Motive::Fighters("Fighters", 64, 32, 0 * 16, 6 * 16);
|
||||
const Motive Motive::Pointer("Pointer", 64, 64, 0 * 16, 12 * 16);
|
||||
const Motive Motive::Pigscene("Pigscene", 64, 64, 4 * 16, 12 * 16);
|
||||
const Motive Motive::BurningSkull("BurningSkull", 64, 64, 8 * 16, 12 * 16);
|
||||
const Motive Motive::Skeleton("Skeleton", 64, 48, 12 * 16, 4 * 16);
|
||||
const Motive Motive::DonkeyKong("DonkeyKong", 64, 48, 12 * 16, 7 * 16);
|
||||
const Motive Motive::Earth("Earth", 32, 32, 0 * 16, 10 * 16, false);
|
||||
const Motive Motive::Wind("Wind", 32, 32, 2 * 16, 10 * 16, false);
|
||||
const Motive Motive::Fire("Fire", 32, 32, 4 * 16, 10 * 16, false);
|
||||
const Motive Motive::Water("Water", 32, 32, 6 * 16, 10 * 16, false);
|
||||
const Motive* Motive::DefaultImage = &Motive::Kebab;
|
||||
|
||||
std::vector<const Motive*> Motive::getAllMotivesAsList() {
|
||||
std::vector<const Motive*> motives;
|
||||
motives.push_back(&Kebab);
|
||||
motives.push_back(&Aztec2);
|
||||
motives.push_back(&Alban);
|
||||
motives.push_back(&Bomb);
|
||||
motives.push_back(&Plant);
|
||||
motives.push_back(&Wasteland);
|
||||
motives.push_back(&Pool);
|
||||
motives.push_back(&Courbet);
|
||||
motives.push_back(&Sea);
|
||||
motives.push_back(&Sunset);
|
||||
motives.push_back(&Creebet);
|
||||
motives.push_back(&Wanderer);
|
||||
motives.push_back(&Graham);
|
||||
motives.push_back(&Match);
|
||||
motives.push_back(&Bust);
|
||||
motives.push_back(&Stage);
|
||||
motives.push_back(&Void);
|
||||
motives.push_back(&SkullAndRoses);
|
||||
motives.push_back(&Fighters);
|
||||
motives.push_back(&Pointer);
|
||||
motives.push_back(&Pigscene);
|
||||
motives.push_back(&BurningSkull);
|
||||
motives.push_back(&Skeleton);
|
||||
motives.push_back(&DonkeyKong);
|
||||
|
||||
motives.push_back(&Earth);
|
||||
motives.push_back(&Wind);
|
||||
motives.push_back(&Fire);
|
||||
motives.push_back(&Water);
|
||||
|
||||
return motives;
|
||||
}
|
||||
|
||||
const Motive* Motive::getMotiveByName( const std::string& name ) {
|
||||
std::vector<const Motive*> allMovies = getAllMotivesAsList();
|
||||
for(std::vector<const Motive*>::iterator i = allMovies.begin(); i != allMovies.end(); ++i) {
|
||||
if((*i)->name == name)
|
||||
return *i;
|
||||
}
|
||||
return DefaultImage;
|
||||
}
|
||||
|
||||
Motive::Motive( std::string name, int w, int h, int uo, int vo, bool isPublic /*= true*/ )
|
||||
: name(name),
|
||||
w(w),
|
||||
h(h),
|
||||
uo(uo),
|
||||
vo(vo),
|
||||
isPublic(isPublic)
|
||||
{}
|
||||
53
src/world/entity/Motive.h
Executable file
53
src/world/entity/Motive.h
Executable file
@@ -0,0 +1,53 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__Motive_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__Motive_H__
|
||||
#include <string>
|
||||
#include <vector>
|
||||
class Motive {
|
||||
public:
|
||||
static const int MAX_MOTIVE_NAME_LENGTH = 13; // "SkullAndRoses".length();
|
||||
|
||||
Motive(std::string name, int w, int h, int uo, int vo, bool isPublic = true);
|
||||
|
||||
static std::vector<const Motive*> getAllMotivesAsList();
|
||||
static const Motive* getMotiveByName(const std::string& name);
|
||||
public:
|
||||
const std::string name;
|
||||
|
||||
const int w, h;
|
||||
const int uo, vo;
|
||||
|
||||
const bool isPublic;
|
||||
|
||||
static const Motive* DefaultImage;
|
||||
static const Motive Kebab;
|
||||
static const Motive Aztec;
|
||||
static const Motive Alban;
|
||||
static const Motive Aztec2;
|
||||
static const Motive Bomb;
|
||||
static const Motive Plant;
|
||||
static const Motive Wasteland;
|
||||
static const Motive Pool;
|
||||
static const Motive Courbet;
|
||||
static const Motive Sea;
|
||||
static const Motive Sunset;
|
||||
static const Motive Creebet;
|
||||
static const Motive Wanderer;
|
||||
static const Motive Graham;
|
||||
static const Motive Match;
|
||||
static const Motive Bust;
|
||||
static const Motive Stage;
|
||||
static const Motive Void;
|
||||
static const Motive SkullAndRoses;
|
||||
static const Motive Fighters;
|
||||
static const Motive Pointer;
|
||||
static const Motive Pigscene;
|
||||
static const Motive BurningSkull;
|
||||
static const Motive Skeleton;
|
||||
static const Motive DonkeyKong;
|
||||
static const Motive Earth;
|
||||
static const Motive Wind;
|
||||
static const Motive Fire;
|
||||
static const Motive Water;
|
||||
};
|
||||
|
||||
#endif /* NET_MINECRAFT_WORLD_ENTITY__Motive_H__ */
|
||||
77
src/world/entity/Painting.cpp
Executable file
77
src/world/entity/Painting.cpp
Executable file
@@ -0,0 +1,77 @@
|
||||
#include "Painting.h"
|
||||
#include "../level/Level.h"
|
||||
#include "../item/Item.h"
|
||||
Painting::Painting( Level* level ) : super(level) {
|
||||
entityRendererId = ER_PAINTING_RENDERER;
|
||||
}
|
||||
|
||||
Painting::Painting( Level* level, int xTile, int yTile, int zTile, int dir )
|
||||
: super(level, xTile, yTile, zTile, dir) {
|
||||
setRandomMotive(dir);
|
||||
|
||||
entityRendererId = ER_PAINTING_RENDERER;
|
||||
}
|
||||
|
||||
Painting::Painting( Level* level, int x, int y, int z, int dir, const std::string& motiveName )
|
||||
: super(level, x, y, z, dir) {
|
||||
motive = Motive::getMotiveByName(motiveName);
|
||||
setDir(dir);
|
||||
entityRendererId = ER_PAINTING_RENDERER;
|
||||
}
|
||||
|
||||
void Painting::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
if(motive != NULL) {
|
||||
tag->putString("Motive", motive->name);
|
||||
}
|
||||
super::addAdditonalSaveData(tag);
|
||||
}
|
||||
|
||||
void Painting::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
std::string motiveName = tag->getString("Motive");
|
||||
motive = Motive::getMotiveByName(motiveName);
|
||||
super::readAdditionalSaveData(tag);
|
||||
}
|
||||
|
||||
int Painting::getWidth() {
|
||||
return motive->w;
|
||||
}
|
||||
|
||||
int Painting::getHeight() {
|
||||
return motive->h;
|
||||
}
|
||||
|
||||
void Painting::dropItem() {
|
||||
if(level->getLevelData()->getGameType() != GameType::Creative)
|
||||
spawnAtLocation(Item::painting->id, 1);
|
||||
}
|
||||
|
||||
int Painting::getEntityTypeId() const {
|
||||
return EntityTypes::IdPainting;
|
||||
}
|
||||
|
||||
void Painting::setRandomMotive( int dir ) {
|
||||
std::vector<const Motive*> allMotives = Motive::getAllMotivesAsList();
|
||||
std::vector<const Motive*> survivableMotives;
|
||||
for(std::vector<const Motive*>::iterator i = allMotives.begin(); i != allMotives.end(); ++i) {
|
||||
if (!(*i)->isPublic)
|
||||
continue;
|
||||
|
||||
motive = *i;
|
||||
setDir(dir);
|
||||
if(survives()) {
|
||||
survivableMotives.push_back(*i);
|
||||
}
|
||||
}
|
||||
if(!survivableMotives.empty()) {
|
||||
this->motive = survivableMotives[sharedRandom.nextInt(survivableMotives.size())];
|
||||
setDir(dir);
|
||||
}
|
||||
else {
|
||||
this->motive = Motive::DefaultImage;
|
||||
setDir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
bool Painting::isPickable() {
|
||||
return true;
|
||||
}
|
||||
27
src/world/entity/Painting.h
Executable file
27
src/world/entity/Painting.h
Executable file
@@ -0,0 +1,27 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__Painting_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__Painting_H__
|
||||
#include "Motive.h"
|
||||
#include "HangingEntity.h"
|
||||
class Painting : public HangingEntity {
|
||||
typedef HangingEntity super;
|
||||
public:
|
||||
Painting(Level* level);
|
||||
Painting(Level* level, int xTile, int yTile, int zTile, int dir);
|
||||
Painting(Level* level, int x, int y, int z, int dir, const std::string& motiveName);
|
||||
|
||||
void setRandomMotive( int dir );
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
|
||||
void dropItem();
|
||||
int getEntityTypeId() const;
|
||||
bool isPickable();
|
||||
public:
|
||||
const Motive* motive;
|
||||
};
|
||||
|
||||
#endif /* NET_MINECRAFT_WORLD_ENTITY__Painting_H__ */
|
||||
248
src/world/entity/PathfinderMob.cpp
Executable file
248
src/world/entity/PathfinderMob.cpp
Executable file
@@ -0,0 +1,248 @@
|
||||
#include "PathfinderMob.h"
|
||||
#include "../level/Level.h"
|
||||
#include "../phys/Vec3.h"
|
||||
#include "../../util/Mth.h"
|
||||
#include "../../util/PerfTimer.h"
|
||||
#include "../../SharedConstants.h"
|
||||
|
||||
#include "ai/Sensing.h"
|
||||
|
||||
|
||||
PathfinderMob::PathfinderMob( Level* level )
|
||||
: super(level),
|
||||
//navigation(this, level, 16),
|
||||
attackTargetId(0),
|
||||
holdGround(false),
|
||||
fleeTime(0)//,
|
||||
//pathfinderMask(0)
|
||||
{
|
||||
sensing = new Sensing(this);
|
||||
navigation = new PathNavigation(this, level, 16);
|
||||
}
|
||||
|
||||
PathfinderMob::~PathfinderMob() {
|
||||
delete navigation;
|
||||
delete sensing;
|
||||
}
|
||||
|
||||
bool PathfinderMob::canSpawn()
|
||||
{
|
||||
return super::canSpawn() && getWalkTargetValue(Mth::floor(x), Mth::floor(bb.y0), Mth::floor(z)) >= 0;
|
||||
}
|
||||
|
||||
bool PathfinderMob::isPathFinding()
|
||||
{
|
||||
return !path.isEmpty();
|
||||
}
|
||||
|
||||
void PathfinderMob::setPath( Path& path )
|
||||
{
|
||||
this->path = path;
|
||||
}
|
||||
|
||||
Entity* PathfinderMob::getAttackTarget()
|
||||
{
|
||||
if (attackTargetId == 0) return NULL;
|
||||
return level->getEntity(attackTargetId);
|
||||
}
|
||||
|
||||
void PathfinderMob::setAttackTarget( Entity* attacker )
|
||||
{
|
||||
attackTargetId = attacker? attacker->entityId : 0;
|
||||
}
|
||||
|
||||
bool PathfinderMob::shouldHoldGround()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void PathfinderMob::updateAi()
|
||||
{
|
||||
TIMER_PUSH("ai");
|
||||
|
||||
if (fleeTime > 0) fleeTime--;
|
||||
holdGround = shouldHoldGround();
|
||||
float maxDist = 16;
|
||||
|
||||
Entity* attackTarget = NULL;
|
||||
if (attackTargetId == 0) {
|
||||
attackTarget = findAttackTarget();
|
||||
if (attackTarget != NULL) {
|
||||
level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
|
||||
attackTargetId = attackTarget->entityId;
|
||||
//LOGI("path.empty: %d\n", path.isEmpty());
|
||||
}
|
||||
} else {
|
||||
attackTarget = level->getEntity(attackTargetId);
|
||||
if (!attackTarget || !attackTarget->isAlive()) {
|
||||
attackTargetId = 0;
|
||||
attackTarget = NULL;
|
||||
} else {
|
||||
attackTargetId = attackTarget->entityId;
|
||||
float d = attackTarget->distanceTo(this);
|
||||
if (canSee(attackTarget)) {
|
||||
checkHurtTarget(attackTarget, d);
|
||||
} else {
|
||||
checkCantSeeTarget(attackTarget, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
TIMER_POP();
|
||||
|
||||
/*
|
||||
* if (holdGround) { xxa = 0; yya = 0; jumping = false; return; }
|
||||
*/
|
||||
|
||||
bool doStroll = false;
|
||||
if (!holdGround && (attackTarget != NULL && (path.isEmpty() || random.nextInt(20) == 0))) {
|
||||
level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
|
||||
} else if (!holdGround) {
|
||||
if (path.isEmpty() && (random.nextInt(180) == 0)) {
|
||||
doStroll = true;
|
||||
} else {
|
||||
if (random.nextInt(120) == 0) doStroll = true;
|
||||
else if (fleeTime > 0 && (fleeTime&7) == 1) doStroll = true;
|
||||
}
|
||||
}
|
||||
if (doStroll) {
|
||||
if (noActionTime < SharedConstants::TicksPerSecond * 5) {
|
||||
findRandomStrollLocation();
|
||||
}
|
||||
}
|
||||
|
||||
int yFloor = Mth::floor(bb.y0 + .5f);
|
||||
|
||||
bool inWater = isInWater();
|
||||
bool inLava = isInLava();
|
||||
xRot = 0;
|
||||
if (path.isEmpty() || random.nextInt(100) == 0) {
|
||||
//super::serverAiStep();
|
||||
super::updateAi();
|
||||
return;
|
||||
}
|
||||
|
||||
TIMER_PUSH("followpath");
|
||||
Vec3 target = path.currentPos(this);
|
||||
float r = bbWidth * 2;
|
||||
bool looping = true;
|
||||
while (looping && target.distanceToSqr(x, target.y, z) < r * r) {
|
||||
path.next();
|
||||
if (path.isDone()) {
|
||||
looping = false;
|
||||
path.destroy();
|
||||
} else target = path.currentPos(this);
|
||||
}
|
||||
|
||||
jumping = false;
|
||||
if (looping) {
|
||||
float xd = target.x - x;
|
||||
float zd = target.z - z;
|
||||
float yd = target.y - yFloor;
|
||||
// float yRotOld = yRot;
|
||||
float yRotD = (float) (Mth::atan2(zd, xd) * 180 / Mth::PI) - 90;
|
||||
float rotDiff = yRotD - yRot;
|
||||
yya = runSpeed;
|
||||
while (rotDiff < -180)
|
||||
rotDiff += 360;
|
||||
while (rotDiff >= 180)
|
||||
rotDiff -= 360;
|
||||
if (rotDiff > MAX_TURN) {
|
||||
rotDiff = MAX_TURN;
|
||||
// yya *= 0.2;
|
||||
}
|
||||
if (rotDiff < -MAX_TURN) {
|
||||
rotDiff = -MAX_TURN;
|
||||
// yya *= 0.2;
|
||||
}
|
||||
yRot += rotDiff;
|
||||
|
||||
if (holdGround) {
|
||||
if (attackTarget != NULL) {
|
||||
float xd2 = attackTarget->x - x;
|
||||
float zd2 = attackTarget->z - z;
|
||||
|
||||
float oldyRot = yRot;
|
||||
yRot = (float) (Mth::atan2(zd2, xd2) * 180 / Mth::PI) - 90;
|
||||
|
||||
rotDiff = ((oldyRot - yRot) + 90) * Mth::PI / 180;
|
||||
xxa = -Mth::sin(rotDiff) * yya * 1.0f;
|
||||
yya = Mth::cos(rotDiff) * yya * 1.0f;
|
||||
}
|
||||
}
|
||||
if (yd > 0) {
|
||||
jumping = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (attackTarget != NULL) {
|
||||
lookAt(attackTarget, 30, 30);
|
||||
}
|
||||
|
||||
if (this->horizontalCollision && !isPathFinding()) jumping = true;
|
||||
if (random.nextFloat() < 0.8f && (inWater || inLava)) jumping = true;
|
||||
|
||||
TIMER_POP();
|
||||
}
|
||||
|
||||
void PathfinderMob::findRandomStrollLocation()
|
||||
{
|
||||
TIMER_PUSH("stroll");
|
||||
bool hasBest = false;
|
||||
int xBest = -1;
|
||||
int yBest = -1;
|
||||
int zBest = -1;
|
||||
float best = -99999;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int xt = Mth::floor(x + random.nextInt(13) - 6);
|
||||
int yt = Mth::floor(y + random.nextInt(7) - 3);
|
||||
int zt = Mth::floor(z + random.nextInt(13) - 6);
|
||||
float value = getWalkTargetValue(xt, yt, zt);
|
||||
if (value > best) {
|
||||
best = value;
|
||||
xBest = xt;
|
||||
yBest = yt;
|
||||
zBest = zt;
|
||||
hasBest = true;
|
||||
}
|
||||
|
||||
}
|
||||
if (hasBest) {
|
||||
//LOGI("Finding a new strolling location! %d, %d, %d (%d, %d, %d) for %p\n", xBest, yBest, zBest, (int)x, (int)y, (int)z, this);
|
||||
level->findPath(&path, this, xBest, yBest, zBest, 10, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0);
|
||||
}
|
||||
TIMER_POP();
|
||||
}
|
||||
|
||||
void PathfinderMob::checkHurtTarget( Entity* target, float d )
|
||||
{
|
||||
}
|
||||
|
||||
void PathfinderMob::checkCantSeeTarget( Entity* target, float d )
|
||||
{
|
||||
if (d > 32)
|
||||
attackTargetId = 0;
|
||||
}
|
||||
|
||||
float PathfinderMob::getWalkTargetValue( int x, int y, int z )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Entity* PathfinderMob::findAttackTarget()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float PathfinderMob::getWalkingSpeedModifier() {
|
||||
float speed = super::getWalkingSpeedModifier();
|
||||
if (fleeTime > 0) speed *= 2;
|
||||
return speed;
|
||||
}
|
||||
|
||||
int PathfinderMob::getNoActionTime() {
|
||||
return noActionTime;
|
||||
}
|
||||
|
||||
PathNavigation* PathfinderMob::getNavigation() {
|
||||
return navigation;
|
||||
}
|
||||
65
src/world/entity/PathfinderMob.h
Executable file
65
src/world/entity/PathfinderMob.h
Executable file
@@ -0,0 +1,65 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__PathfinderMob_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__PathfinderMob_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include "Mob.h"
|
||||
#include "ai/PathNavigation.h"
|
||||
#include "../level/pathfinder/Path.h"
|
||||
|
||||
class Level;
|
||||
class Sensing;
|
||||
|
||||
typedef struct AIData {
|
||||
AIData():
|
||||
target(NULL)
|
||||
{}
|
||||
|
||||
Mob* target;
|
||||
} AIData;
|
||||
|
||||
class PathfinderMob: public Mob
|
||||
{
|
||||
typedef Mob super;
|
||||
static const int MAX_TURN = 30;
|
||||
public:
|
||||
PathfinderMob(Level* level);
|
||||
~PathfinderMob();
|
||||
|
||||
bool canSpawn();
|
||||
|
||||
bool isPathFinding();
|
||||
void setPath(Path& path);
|
||||
|
||||
virtual Entity* getAttackTarget();
|
||||
virtual void setAttackTarget(Entity* attacker);
|
||||
|
||||
virtual float getWalkTargetValue(int x, int y, int z);
|
||||
int getNoActionTime();
|
||||
|
||||
PathNavigation* getNavigation();
|
||||
protected:
|
||||
virtual Entity* findAttackTarget();
|
||||
|
||||
virtual void checkHurtTarget(Entity* target, float d);
|
||||
virtual void checkCantSeeTarget(Entity* target, float d);
|
||||
|
||||
virtual float getWalkingSpeedModifier();
|
||||
|
||||
virtual bool shouldHoldGround();
|
||||
|
||||
void updateAi();
|
||||
|
||||
virtual void findRandomStrollLocation();
|
||||
int attackTargetId;
|
||||
bool holdGround;
|
||||
int fleeTime;
|
||||
public:
|
||||
static const int CAN_OPEN_DOORS = 1;
|
||||
static const int AVOID_WATER = 2;
|
||||
//int pathfinderMask;
|
||||
private:
|
||||
Path path;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__PathfinderMob_H__*/
|
||||
17
src/world/entity/SharedFlags.h
Executable file
17
src/world/entity/SharedFlags.h
Executable file
@@ -0,0 +1,17 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__SharedFlags_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__SharedFlags_H__
|
||||
|
||||
class SharedFlagsInformation {
|
||||
public:
|
||||
enum SharedFlags {
|
||||
FLAG_ONFIRE = 0,
|
||||
FLAG_SNEAKING = 1,
|
||||
FLAG_RIDING = 2,
|
||||
FLAG_SPRINTING = 3,
|
||||
FLAG_USINGITEM = 4
|
||||
};
|
||||
typedef char SharedFlagsInformationType;
|
||||
|
||||
static const unsigned int DATA_SHARED_FLAGS_ID = 0;
|
||||
};
|
||||
#endif /* NET_MINECRAFT_WORLD_ENTITY__SharedFlags_H__ */
|
||||
250
src/world/entity/SynchedEntityData.cpp
Executable file
250
src/world/entity/SynchedEntityData.cpp
Executable file
@@ -0,0 +1,250 @@
|
||||
#include "SynchedEntityData.h"
|
||||
|
||||
|
||||
SynchedEntityData::SynchedEntityData()
|
||||
: _isDirty(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SynchedEntityData::~SynchedEntityData()
|
||||
{
|
||||
for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) {
|
||||
delete (it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void SynchedEntityData::pack( DataList* items, IDataOutput* output )
|
||||
{
|
||||
if (items != NULL) {
|
||||
for (DataList::iterator it = items->begin(); it != items->end(); ++it)
|
||||
writeDataItem(output, *it);
|
||||
}
|
||||
// add an eof
|
||||
output->writeByte(EOF_MARKER);
|
||||
}
|
||||
|
||||
SynchedEntityData::DataList SynchedEntityData::packDirty()
|
||||
{
|
||||
DataList result;
|
||||
if (_isDirty) {
|
||||
for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) {
|
||||
DataItem* dataItem = it->second;
|
||||
if (dataItem->isDirty()) {
|
||||
dataItem->setDirty(false);
|
||||
result.push_back(dataItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
_isDirty = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SynchedEntityData::packAll( IDataOutput* output ) const
|
||||
{
|
||||
for (Map::const_iterator cit = itemsById.begin(); cit != itemsById.end(); ++cit)
|
||||
SynchedEntityData::writeDataItem(output, cit->second);
|
||||
|
||||
// add an eof
|
||||
output->writeByte(EOF_MARKER);
|
||||
}
|
||||
|
||||
SynchedEntityData::DataList SynchedEntityData::unpack( IDataInput* input )
|
||||
{
|
||||
DataList result;
|
||||
|
||||
int currentHeader = input->readByte();
|
||||
|
||||
while (currentHeader != EOF_MARKER) {
|
||||
// split type and id
|
||||
int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT;
|
||||
int itemId = (currentHeader & MAX_ID_VALUE);
|
||||
|
||||
//LOGI("unpacking: %d, %d\n", itemId, itemType);
|
||||
|
||||
DataItem* item = NULL;
|
||||
switch (itemType) {
|
||||
case TYPE_BYTE:
|
||||
item = new DataItem2<TypeChar>(itemType, itemId, input->readByte());
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
item = new DataItem2<TypeShort>(itemType, itemId, input->readShort());
|
||||
break;
|
||||
case TYPE_INT:
|
||||
item = new DataItem2<TypeInt>(itemType, itemId, input->readInt());
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
item = new DataItem2<TypeFloat>(itemType, itemId, input->readFloat());
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
item = new DataItem2<std::string>(itemType, itemId, input->readString());
|
||||
break;
|
||||
case TYPE_ITEMINSTANCE: {
|
||||
int id = input->readShort();
|
||||
int count = input->readByte();
|
||||
int auxValue = input->readShort();
|
||||
item = new DataItem2<ItemInstance>(itemType, itemId, ItemInstance(id, count, auxValue));
|
||||
}
|
||||
break;
|
||||
case TYPE_POS: {
|
||||
int x = input->readInt();
|
||||
int y = input->readInt();
|
||||
int z = input->readInt();
|
||||
item = new DataItem2<Pos>(itemType, itemId, Pos(x, y, z));
|
||||
}
|
||||
break;
|
||||
}
|
||||
result.push_back(item);
|
||||
|
||||
currentHeader = input->readByte();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SynchedEntityData::assignValues( DataList* items )
|
||||
{
|
||||
for (DataList::const_iterator it = items->begin(); it != items->end(); ++it) {
|
||||
|
||||
//for (DataItem item : items) {
|
||||
DataItem* item = *it;
|
||||
Map::iterator jt = itemsById.find(item->getId());
|
||||
//DataItem dataItem = itemsById.get(item.getId());
|
||||
if (jt != itemsById.end()) {
|
||||
switch (item->getType()) {
|
||||
case TYPE_BYTE : set(jt->second, ((DataItem2<TypeChar>*)item)->data); break;
|
||||
case TYPE_SHORT: set(jt->second, ((DataItem2<TypeShort>*)item)->data); break;
|
||||
case TYPE_INT : set(jt->second, ((DataItem2<TypeInt>*)item)->data); break;
|
||||
case TYPE_FLOAT: set(jt->second, ((DataItem2<TypeFloat>*)item)->data); break;
|
||||
case TYPE_STRING:set(jt->second, ((DataItem2<std::string>*)item)->data); break;
|
||||
case TYPE_ITEMINSTANCE: set(jt->second, ((DataItem2<ItemInstance>*)item)->data); break;
|
||||
case TYPE_POS: set(jt->second, ((DataItem2<Pos>*)item)->data); break;
|
||||
default:
|
||||
LOGE("Incorrect type id: %d\n", item->getType());
|
||||
break;
|
||||
}
|
||||
//dataItem->setValue(item->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SynchedEntityData::writeDataItem( IDataOutput* output, const DataItem* dataItem )
|
||||
{
|
||||
//LOGI("write: %d, %d\n", dataItem->getId(), dataItem->getType());
|
||||
|
||||
// pack type and id
|
||||
//LOGI("dataItem: %d\n", dataItem);
|
||||
int header = ((dataItem->getType() << TYPE_SHIFT) | (dataItem->getId() & MAX_ID_VALUE)) & 0xff;
|
||||
output->writeByte(header);
|
||||
|
||||
// write value
|
||||
switch (dataItem->getType()) {
|
||||
case TYPE_BYTE:
|
||||
output->writeByte(((DataItem2<TypeChar>*)dataItem)->data);
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
output->writeShort(((DataItem2<TypeShort>*)dataItem)->data);
|
||||
break;
|
||||
case TYPE_INT:
|
||||
output->writeInt(((DataItem2<TypeInt>*)dataItem)->data);
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
output->writeFloat(((DataItem2<TypeFloat>*)dataItem)->data);
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
output->writeString(((DataItem2<std::string>*)dataItem)->data);
|
||||
break;
|
||||
case TYPE_ITEMINSTANCE: {
|
||||
const ItemInstance& instance = ((DataItem2<ItemInstance>*)dataItem)->data;
|
||||
output->writeShort(instance.getItem()->id);
|
||||
output->writeByte(instance.count);
|
||||
output->writeShort(instance.getAuxValue());
|
||||
}
|
||||
break;
|
||||
case TYPE_POS: {
|
||||
const Pos& instance = ((DataItem2<Pos>*)dataItem)->data;
|
||||
output->writeInt(instance.x);
|
||||
output->writeInt(instance.y);
|
||||
output->writeInt(instance.z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SynchedEntityData::TypeChar SynchedEntityData::getByte( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_BYTE) {
|
||||
return ((DataItem2<TypeChar>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SynchedEntityData::TypeShort SynchedEntityData::getShort( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_SHORT) {
|
||||
return ((DataItem2<TypeShort>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SynchedEntityData::TypeInt SynchedEntityData::getInt( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_INT) {
|
||||
return ((DataItem2<TypeInt>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SynchedEntityData::TypeFloat SynchedEntityData::getFloat( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_FLOAT) {
|
||||
return ((DataItem2<TypeFloat>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string SynchedEntityData::getString( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_STRING) {
|
||||
return ((DataItem2<std::string>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
ItemInstance SynchedEntityData::getItemInstance( int id )
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_ITEMINSTANCE) {
|
||||
return ((DataItem2<ItemInstance>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return ItemInstance();
|
||||
}
|
||||
|
||||
Pos SynchedEntityData::getPos( int id ) const
|
||||
{
|
||||
Map::const_iterator it = itemsById.find(id);
|
||||
if (it != itemsById.end()) {
|
||||
if (it->second->getType() == TYPE_POS) {
|
||||
return ((DataItem2<Pos>*)it->second)->data;
|
||||
}
|
||||
}
|
||||
return Pos();
|
||||
}
|
||||
251
src/world/entity/SynchedEntityData.h
Executable file
251
src/world/entity/SynchedEntityData.h
Executable file
@@ -0,0 +1,251 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY__SynchedEntityData_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY__SynchedEntityData_H__
|
||||
|
||||
//package net.minecraft.world.entity;
|
||||
|
||||
#include "../Pos.h"
|
||||
#include "../../network/Packet.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
#include "../item/Item.h"
|
||||
#include "../../util/DataIO.h"
|
||||
|
||||
class DataItem {
|
||||
public:
|
||||
DataItem(int type, int id)
|
||||
: type(type),
|
||||
id(id),
|
||||
dirty(true)
|
||||
{}
|
||||
virtual ~DataItem() {}
|
||||
|
||||
int getId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
int getType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
bool isDirty() const {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
void setDirty(bool dirty) {
|
||||
this->dirty = dirty;
|
||||
}
|
||||
virtual bool isDataEqual(const DataItem& rhs) const {
|
||||
return type == rhs.type;
|
||||
}
|
||||
private:
|
||||
const int type;
|
||||
const int id;
|
||||
bool dirty;
|
||||
/*
|
||||
public:
|
||||
// attn: Very un-typesafe, but let's go
|
||||
union {
|
||||
char _char;
|
||||
short _short;
|
||||
int _int;
|
||||
float _float;
|
||||
std::string _String;
|
||||
ItemInstance _ItemInstance;
|
||||
Pos _Pos;
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DataItem2: public DataItem {
|
||||
typedef DataItem super;
|
||||
public:
|
||||
DataItem2(int type, int id, const T& data)
|
||||
: super(type, id),
|
||||
data(data)
|
||||
{}
|
||||
void setFlag(int flag) {
|
||||
data = data | (1 << flag);
|
||||
}
|
||||
void clearFlag(int flag) {
|
||||
data = data & ~(1 << flag);
|
||||
}
|
||||
bool getFlag(int flag) const {
|
||||
return (data & (1 << flag)) != 0;
|
||||
}
|
||||
T data;
|
||||
};
|
||||
|
||||
/*
|
||||
#define DataItemClassFactory2(Postfix, TypeName) \
|
||||
class DataItem_ ## Postfix : public DataItem { \
|
||||
typedef DataItem super; \
|
||||
public: \
|
||||
DataItem_ ## Postfix(int type, int id, #Typename data) \
|
||||
: super(type), \
|
||||
data(data) \
|
||||
{} \
|
||||
virtual bool isDataEqual(const DataItem& rhs) const { \
|
||||
if (!super::isDataEqual(rhs)) return; \
|
||||
return data == (DataItem_ ## #Postfix&)rhs.data; \
|
||||
} \
|
||||
#Typename data; \
|
||||
};
|
||||
#define DataItemClassFactory(TypeName) DataItemClassFactory2(TypeName, TypeName)
|
||||
|
||||
DataItemClassFactory(char);
|
||||
DataItemClassFactory(short);
|
||||
DataItemClassFactory(int);
|
||||
DataItemClassFactory(float);
|
||||
DataItemClassFactory(ItemInstance);
|
||||
DataItemClassFactory(Pos);
|
||||
DataItemClassFactory2(String, std::string);
|
||||
*/
|
||||
|
||||
class SynchedEntityData {
|
||||
public:
|
||||
static const int MAX_STRING_DATA_LENGTH = 64;
|
||||
static const int EOF_MARKER = 0x7f;
|
||||
|
||||
typedef signed char TypeChar;
|
||||
typedef short TypeShort;
|
||||
typedef int TypeInt;
|
||||
typedef float TypeFloat;
|
||||
private:
|
||||
static const int TYPE_BYTE = 0;
|
||||
static const int TYPE_SHORT = 1;
|
||||
static const int TYPE_INT = 2;
|
||||
static const int TYPE_FLOAT = 3;
|
||||
static const int TYPE_STRING = 4;
|
||||
// special types (max possible value is 7):
|
||||
static const int TYPE_ITEMINSTANCE = 5;
|
||||
static const int TYPE_POS = 6;
|
||||
|
||||
// must have enough bits to fit the type
|
||||
static const int TYPE_MASK = 0xe0;
|
||||
static const int TYPE_SHIFT = 5;
|
||||
|
||||
// the id value must fit in the remaining bits
|
||||
static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff;
|
||||
|
||||
typedef std::map<int, DataItem*> Map;
|
||||
public:
|
||||
typedef std::vector<DataItem*> DataList;
|
||||
|
||||
SynchedEntityData();
|
||||
|
||||
~SynchedEntityData();
|
||||
|
||||
int getTypeId(const TypeChar &) { return TYPE_BYTE; }
|
||||
int getTypeId(const TypeShort&) { return TYPE_SHORT; }
|
||||
int getTypeId(const TypeInt&) { return TYPE_INT; }
|
||||
int getTypeId(const TypeFloat&) { return TYPE_FLOAT; }
|
||||
int getTypeId(const std::string&){ return TYPE_STRING; }
|
||||
int getTypeId(const ItemInstance&){return TYPE_ITEMINSTANCE; }
|
||||
int getTypeId(const Pos&) { return TYPE_POS; }
|
||||
|
||||
template <class T>
|
||||
void define(int idd, const T& value) {
|
||||
int type = getTypeId(value);
|
||||
|
||||
if (idd > MAX_ID_VALUE) {
|
||||
LOGE("Data value id is too big with %d! (Max is %d )", idd, MAX_ID_VALUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemsById.find(idd) != itemsById.end()) {
|
||||
LOGE("Duplicate id value for %d!\n", idd);
|
||||
return;
|
||||
}
|
||||
|
||||
DataItem* dataItem = new DataItem2<T>(type, idd, value);
|
||||
itemsById.insert(std::make_pair(idd, dataItem));
|
||||
}
|
||||
|
||||
TypeChar getByte(int id) const;
|
||||
TypeShort getShort(int id) const;
|
||||
TypeInt getInt(int id) const;
|
||||
TypeFloat getFloat(int id) const;
|
||||
std::string getString(int id) const;
|
||||
ItemInstance getItemInstance(int id);
|
||||
Pos getPos(int id) const;
|
||||
|
||||
template <class T>
|
||||
void set(int id, const T& value) {
|
||||
set( itemsById[id], value );
|
||||
}
|
||||
template <class T>
|
||||
void set(DataItem* dataItem, const T& value) {
|
||||
if (!dataItem) {
|
||||
LOGE("DataItem not found!\n");
|
||||
return;
|
||||
}
|
||||
if (dataItem->getType() == getTypeId(value)) {
|
||||
DataItem2<T>* d = (DataItem2<T>*)dataItem;
|
||||
if (!(d->data == value)) {
|
||||
d->data = value;
|
||||
dataItem->setDirty(true);
|
||||
_isDirty = true;
|
||||
}
|
||||
} else {
|
||||
LOGE("ERROR: Id %d is not correct type. %d != %d!\n", dataItem->getId(), dataItem->getType(), getTypeId(value));
|
||||
}
|
||||
}
|
||||
/// Set flag bit. Flag is bit shifted.
|
||||
template <class T>
|
||||
void setFlag(int id, int flag) {
|
||||
DataItem2<T>* item = (DataItem2<T>*)itemsById[id];
|
||||
bool oldFlag = item->getFlag(flag);
|
||||
item->setFlag(flag);
|
||||
if(item->getFlag(flag) != oldFlag) {
|
||||
markDirty(id);
|
||||
}
|
||||
}
|
||||
/// Clear flag bit. Flag is bit shifted.
|
||||
template <class T>
|
||||
void clearFlag(int id, int flag) {
|
||||
DataItem2<T>* item = (DataItem2<T>*)itemsById[id];
|
||||
bool oldFlag = item->getFlag(flag);
|
||||
item->clearFlag(flag);
|
||||
if(item->getFlag(flag) != oldFlag) {
|
||||
markDirty(id);
|
||||
}
|
||||
}
|
||||
/// Get flag bit. Flag is bit shifted.
|
||||
template <class T>
|
||||
bool getFlag(int id, int flag) {
|
||||
const DataItem2<T>* item = (const DataItem2<T>*)itemsById[id];
|
||||
return item->getFlag(flag);
|
||||
}
|
||||
|
||||
void markDirty(int id) {
|
||||
itemsById[id]->setDirty(true);
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
bool isDirty() const {
|
||||
return _isDirty;
|
||||
}
|
||||
|
||||
static void pack(DataList* items, IDataOutput* output);
|
||||
|
||||
DataList packDirty();
|
||||
|
||||
void packAll(IDataOutput* output) const;
|
||||
|
||||
static DataList unpack(IDataInput* input);
|
||||
|
||||
/**
|
||||
* Assigns values from a list of data items.
|
||||
*
|
||||
* @param items
|
||||
*/
|
||||
void assignValues(DataList* items);
|
||||
|
||||
private:
|
||||
static void writeDataItem(IDataOutput* output, const DataItem* dataItem);
|
||||
|
||||
Map itemsById;
|
||||
bool _isDirty;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY__SynchedEntityData_H__*/
|
||||
346
src/world/entity/ai/PathNavigation.h
Executable file
346
src/world/entity/ai/PathNavigation.h
Executable file
@@ -0,0 +1,346 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI__PathNavigation_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI__PathNavigation_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai;
|
||||
|
||||
#include "../Mob.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../level/material/Material.h"
|
||||
#include "../../level/tile/Tile.h"
|
||||
#include "../../phys/Vec3.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "../../level/pathfinder/Path.h"
|
||||
#include "control/MoveControl.h"
|
||||
#include "../../../util/MemUtils.h"
|
||||
|
||||
class PathNavigation
|
||||
{
|
||||
public:
|
||||
PathNavigation(Mob* mob, Level* level, float maxDist)
|
||||
: mob(mob),
|
||||
level(level),
|
||||
maxDist(maxDist),
|
||||
_tick(0),
|
||||
avoidSun(false),
|
||||
avoidWater(false),
|
||||
canOpenDoors(false),
|
||||
lastStuckCheckPos(0, 0, 0),
|
||||
speed(0),
|
||||
lastStuckCheck(0),
|
||||
path(NULL),
|
||||
deletePath(false)
|
||||
{
|
||||
}
|
||||
~PathNavigation() {
|
||||
deletePathIfNeeded();
|
||||
}
|
||||
|
||||
void setSpeed(float speed) {
|
||||
this->speed = speed;
|
||||
}
|
||||
|
||||
Path* createPath(float x, float y, float z) {
|
||||
//LOGI("can update? %d\n", canUpdatePath());
|
||||
if (!canUpdatePath())
|
||||
return NULL;
|
||||
Path* p = new Path();
|
||||
level->findPath(p, mob, Mth::floor(x), (int) y, Mth::floor(z), maxDist, canOpenDoors, avoidWater);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool moveTo(float x, float y, float z, float speed) {
|
||||
Path* newPath = createPath(x, y, z);
|
||||
return moveTo(newPath, speed, true);
|
||||
}
|
||||
|
||||
Path* createPath(Mob* target) {
|
||||
//LOGI("can update? %d\n", canUpdatePath());
|
||||
if (!canUpdatePath())
|
||||
return NULL;
|
||||
Path* p = new Path();
|
||||
level->findPath(p, mob, target, maxDist, canOpenDoors, avoidWater);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool moveTo(Mob* target, float speed) {
|
||||
Path* newPath = createPath(target);
|
||||
//if (!newPath->isEmpty()) return moveTo(newPath, speed);
|
||||
if (newPath) return moveTo(newPath, speed, true);
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool moveTo(Path* newPath, float speed, bool navIsPathOwner) {
|
||||
if (newPath == NULL) {
|
||||
deletePathIfNeeded();
|
||||
return false;
|
||||
}
|
||||
//if (newPath.isEmpty()) {
|
||||
// path.destroy();
|
||||
// return false;
|
||||
//}
|
||||
|
||||
Node* last = newPath->last();
|
||||
if (last) {
|
||||
//LOGI("> %d, %d, %d in %d steps\n", last->x, last->y, last->z, newPath->getSize());
|
||||
}
|
||||
|
||||
/*if (!newPath->sameAs(path))*/ {
|
||||
// Delete old path if we are owner
|
||||
deletePathIfNeeded();
|
||||
path = newPath;
|
||||
deletePath = navIsPathOwner;
|
||||
}
|
||||
if (avoidSun) trimPathFromSun();
|
||||
if (path->getSize() == 0) return false;
|
||||
|
||||
this->speed = speed;
|
||||
Vec3 mobPos = getTempMobPos();
|
||||
lastStuckCheck = _tick;
|
||||
lastStuckCheckPos.x = mobPos.x;
|
||||
lastStuckCheckPos.y = mobPos.y;
|
||||
lastStuckCheckPos.z = mobPos.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Ref<Path>* getPath() {
|
||||
Path* getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
++_tick;
|
||||
//LOGI("hehe %d\n", _tick);
|
||||
if (isDone()) return;
|
||||
|
||||
//LOGI("hehe2 %d %d\n", _tick, canUpdatePath());
|
||||
if (canUpdatePath()) updatePath();
|
||||
|
||||
//LOGI("hehe3 %d\n", _tick);
|
||||
if (isDone()) {
|
||||
//LOGI("done!\n");
|
||||
return;
|
||||
}
|
||||
Vec3 target = path->currentPos(mob);
|
||||
//LOGI("hehe4 %d\n", _tick);
|
||||
|
||||
mob->getMoveControl()->setWantedPosition(target.x, target.y, target.z, speed);
|
||||
}
|
||||
|
||||
bool isDone() {
|
||||
return !path || path->isDone();// path == NULL || path.isDone();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
deletePathIfNeeded();
|
||||
//if (path) {
|
||||
// path->destroy(); //@?
|
||||
// path = NULL;
|
||||
//}
|
||||
}
|
||||
|
||||
private:
|
||||
void deletePathIfNeeded() {
|
||||
//return;
|
||||
if (deletePath && path) {
|
||||
LOGI("nav-deleting %p (%d)\n", path, path->id);
|
||||
delete path;
|
||||
//deletePath = false;
|
||||
}
|
||||
path = NULL;
|
||||
}
|
||||
|
||||
void updatePath() {
|
||||
Vec3 mobPos = getTempMobPos();
|
||||
|
||||
Path& path = *this->path;
|
||||
|
||||
// find first elevations in path
|
||||
int firstElevation = path.getSize();
|
||||
for (int i = path.getIndex(); i < path.getSize(); ++i)
|
||||
if (path.get(i)->y != (int) mobPos.y) {
|
||||
firstElevation = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// remove those within way point radius (this is not optimal, should
|
||||
// check canWalkDirectly also) possibly only check next as well
|
||||
float waypointRadiusSqr = mob->bbWidth * mob->bbWidth;
|
||||
for (int i = path.getIndex(); i < firstElevation; ++i) {
|
||||
if (mobPos.distanceToSqr(path.getPos(mob, i)) < waypointRadiusSqr) {
|
||||
path.setIndex(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// smooth remaining on same elevation
|
||||
int sx = (int)ceil(mob->bbWidth);
|
||||
int sy = (int) mob->bbHeight + 1;
|
||||
int sz = sx;
|
||||
for (int i = firstElevation - 1; i >= path.getIndex(); --i) {
|
||||
if (canMoveDirectly(mobPos, path.getPos(mob, i), sx, sy, sz)) {
|
||||
path.setIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// stuck detection (probably pushed off path)
|
||||
if (_tick - lastStuckCheck > 100) {
|
||||
if (mobPos.distanceToSqr(lastStuckCheckPos) < 1.5 * 1.5) stop();
|
||||
lastStuckCheck = _tick;
|
||||
lastStuckCheckPos.x = mobPos.x;
|
||||
lastStuckCheckPos.y = mobPos.y;
|
||||
lastStuckCheckPos.z = mobPos.z;
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 getTempMobPos() {
|
||||
return Vec3(mob->x, (float)getSurfaceY(), mob->z);
|
||||
}
|
||||
|
||||
int getSurfaceY() {
|
||||
if (!mob->isInWater()) return (int) (mob->bb.y0 + 0.5);
|
||||
|
||||
int surface = (int) (mob->bb.y0);
|
||||
int tileId = level->getTile(Mth::floor(mob->x), surface, Mth::floor(mob->z));
|
||||
int steps = 0;
|
||||
while (tileId == Tile::water->id || tileId == Tile::calmWater->id) {
|
||||
++surface;
|
||||
tileId = level->getTile(Mth::floor(mob->x), surface, Mth::floor(mob->z));
|
||||
if (++steps > 16) return (int) (mob->bb.y0);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
bool canUpdatePath() {
|
||||
return mob->onGround || isInLiquid();
|
||||
}
|
||||
|
||||
bool isInLiquid() {
|
||||
return mob->isInWater() || mob->isInLava();
|
||||
}
|
||||
|
||||
void trimPathFromSun() {
|
||||
if (level->canSeeSky(Mth::floor(mob->x), (int) (mob->bb.y0 + 0.5), Mth::floor(mob->z)))
|
||||
return;
|
||||
|
||||
Path& path = *this->path;
|
||||
|
||||
for (int i = 0; i < path.getSize(); ++i) {
|
||||
Node* n = path.get(i);
|
||||
if (level->canSeeSky(n->x, n->y, n->z)) {
|
||||
path.setSize(i - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool canMoveDirectly(const Vec3& startPos, const Vec3& stopPos, int sx, int sy, int sz) {
|
||||
|
||||
int gridPosX = Mth::floor(startPos.x);
|
||||
int gridPosZ = Mth::floor(startPos.z);
|
||||
|
||||
float dirX = stopPos.x - startPos.x;
|
||||
float dirZ = stopPos.z - startPos.z;
|
||||
float distSqr = dirX * dirX + dirZ * dirZ;
|
||||
if (distSqr < 0.00001f) return false;
|
||||
|
||||
float nf = Mth::invSqrt(distSqr);
|
||||
dirX *= nf;
|
||||
dirZ *= nf;
|
||||
|
||||
sx += 2;
|
||||
sz += 2;
|
||||
if (!canWalkOn(gridPosX, (int) startPos.y, gridPosZ, sx, sy, sz, startPos, dirX, dirZ)) return false;
|
||||
sx -= 2;
|
||||
sz -= 2;
|
||||
|
||||
float deltaX = 1 / Mth::abs(dirX);
|
||||
float deltaZ = 1 / Mth::abs(dirZ);
|
||||
|
||||
float maxX = gridPosX * 1 - startPos.x;
|
||||
float maxZ = gridPosZ * 1 - startPos.z;
|
||||
if (dirX >= 0) maxX += 1;
|
||||
if (dirZ >= 0) maxZ += 1;
|
||||
maxX /= dirX;
|
||||
maxZ /= dirZ;
|
||||
|
||||
int stepX = dirX < 0 ? -1 : 1;
|
||||
int stepZ = dirZ < 0 ? -1 : 1;
|
||||
int gridGoalX = Mth::floor(stopPos.x);
|
||||
int gridGoalZ = Mth::floor(stopPos.z);
|
||||
int currentDirX = gridGoalX - gridPosX;
|
||||
int currentDirZ = gridGoalZ - gridPosZ;
|
||||
while (currentDirX * stepX > 0 || currentDirZ * stepZ > 0) {
|
||||
if (maxX < maxZ) {
|
||||
maxX += deltaX;
|
||||
gridPosX += stepX;
|
||||
currentDirX = gridGoalX - gridPosX;
|
||||
} else {
|
||||
maxZ += deltaZ;
|
||||
gridPosZ += stepZ;
|
||||
currentDirZ = gridGoalZ - gridPosZ;
|
||||
}
|
||||
|
||||
if (!canWalkOn(gridPosX, (int) startPos.y, gridPosZ, sx, sy, sz, startPos, dirX, dirZ)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canWalkOn(int x, int y, int z, int sx, int sy, int sz, const Vec3& startPos, float goalDirX, float goalDirZ) {
|
||||
int startX = x - sx / 2;
|
||||
int startZ = z - sz / 2;
|
||||
|
||||
if (!canWalkAbove(startX, y, startZ, sx, sy, sz, startPos, goalDirX, goalDirZ)) return false;
|
||||
|
||||
// lava or water or air under
|
||||
for (int xx = startX; xx < startX + sx; xx++) {
|
||||
for (int zz = startZ; zz < startZ + sz; zz++) {
|
||||
float dirX = xx + 0.5f - startPos.x;
|
||||
float dirZ = zz + 0.5f - startPos.z;
|
||||
if (dirX * goalDirX + dirZ * goalDirZ < 0) continue;
|
||||
int tile = level->getTile(xx, y - 1, zz);
|
||||
if (tile <= 0) return false;
|
||||
const Material* m = Tile::tiles[tile]->material;
|
||||
if (m == Material::water && !mob->isInWater()) return false;
|
||||
if (m == Material::lava) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canWalkAbove(int startX, int startY, int startZ, int sx, int sy, int sz, const Vec3& startPos, float goalDirX, float goalDirZ) {
|
||||
for (int xx = startX; xx < startX + sx; xx++) {
|
||||
for (int yy = startY; yy < startY + sy; yy++) {
|
||||
for (int zz = startZ; zz < startZ + sz; zz++) {
|
||||
|
||||
float dirX = xx + 0.5f - startPos.x;
|
||||
float dirZ = zz + 0.5f - startPos.z;
|
||||
if (dirX * goalDirX + dirZ * goalDirZ < 0) continue;
|
||||
int tile = level->getTile(xx, yy, zz);
|
||||
if (tile <= 0) continue;
|
||||
if (Tile::tiles[tile]->material->blocksMotion()) return false;
|
||||
//if (!Tile::tiles[tile]->isPathfindable(level, xx, yy, zz)) return false; //@todo
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
Mob* mob;
|
||||
Level* level;
|
||||
Path* path;
|
||||
bool deletePath;
|
||||
Ref<Path>* refPath;
|
||||
float speed;
|
||||
float maxDist;
|
||||
int _tick;
|
||||
int lastStuckCheck;
|
||||
Vec3 lastStuckCheckPos;
|
||||
public:
|
||||
bool avoidWater;
|
||||
bool avoidSun;
|
||||
bool canOpenDoors;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI__PathNavigation_H__*/
|
||||
38
src/world/entity/ai/Sensing.h
Executable file
38
src/world/entity/ai/Sensing.h
Executable file
@@ -0,0 +1,38 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_SENSING__Sensing_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_SENSING__Sensing_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.sensing;
|
||||
|
||||
#include <set>
|
||||
|
||||
class Sensing {
|
||||
typedef std::set<Entity*> EntitySet;
|
||||
public:
|
||||
Sensing(Mob* mob)
|
||||
: mob(mob)
|
||||
{}
|
||||
|
||||
void tick() {
|
||||
seen.clear();
|
||||
unseen.clear();
|
||||
}
|
||||
|
||||
bool canSee(Entity* target) {
|
||||
EntitySet::const_iterator cSeen = seen.find(target);
|
||||
if (cSeen != seen.end()) return true;
|
||||
|
||||
EntitySet::const_iterator cUnseen = unseen.find(target);
|
||||
if (cUnseen != unseen.end()) return false;
|
||||
|
||||
bool canSee = mob->canSee(target);
|
||||
if (canSee) seen.insert(target);
|
||||
else unseen.insert(target);
|
||||
return canSee;
|
||||
}
|
||||
private:
|
||||
Mob* mob;
|
||||
EntitySet seen;
|
||||
EntitySet unseen;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_SENSING__Sensing_H__*/
|
||||
13
src/world/entity/ai/control/Control.h
Executable file
13
src/world/entity/ai/control/Control.h
Executable file
@@ -0,0 +1,13 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__Control_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__Control_H__
|
||||
|
||||
//package net.minecraft.world.entity->ai.control;
|
||||
|
||||
class Control {
|
||||
public:
|
||||
static const int MoveControlFlag = 1;
|
||||
static const int LookControlFlag = 2;
|
||||
static const int JumpControlFlag = 4;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__Control_H__*/
|
||||
31
src/world/entity/ai/control/JumpControl.h
Executable file
31
src/world/entity/ai/control/JumpControl.h
Executable file
@@ -0,0 +1,31 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__JumpControl_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__JumpControl_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.control;
|
||||
|
||||
#include "Control.h"
|
||||
#include "../../Mob.h"
|
||||
|
||||
class JumpControl: public Control
|
||||
{
|
||||
public:
|
||||
JumpControl(Mob* mob)
|
||||
: mob(mob),
|
||||
_jump(false)
|
||||
{
|
||||
}
|
||||
|
||||
void jump() {
|
||||
_jump = true;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
mob->setJumping(_jump);
|
||||
_jump = false;
|
||||
}
|
||||
private:
|
||||
Mob* mob;
|
||||
bool _jump;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__JumpControl_H__*/
|
||||
70
src/world/entity/ai/control/MoveControl.cpp
Executable file
70
src/world/entity/ai/control/MoveControl.cpp
Executable file
@@ -0,0 +1,70 @@
|
||||
#include "MoveControl.h"
|
||||
#include "JumpControl.h"
|
||||
|
||||
const float MoveControl::MAX_TURN = 30;
|
||||
|
||||
const float MoveControl::MIN_SPEED = 0.0005f;
|
||||
const float MoveControl::MIN_SPEED_SQR = MIN_SPEED * MIN_SPEED;
|
||||
|
||||
|
||||
MoveControl::MoveControl( Mob* mob )
|
||||
: mob(mob),
|
||||
wantedX(mob->x),
|
||||
wantedY(mob->y),
|
||||
wantedZ(mob->z),
|
||||
_hasWanted(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool MoveControl::hasWanted() {
|
||||
return _hasWanted;
|
||||
}
|
||||
|
||||
float MoveControl::getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
void MoveControl::setWantedPosition( float x, float y, float z, float speed ) {
|
||||
//LOGI("> %f, %f, %f\n", x, y, z);
|
||||
wantedX = x;
|
||||
wantedY = y;
|
||||
wantedZ = z;
|
||||
this->speed = speed;
|
||||
_hasWanted = true;
|
||||
}
|
||||
|
||||
void MoveControl::tick() {
|
||||
mob->setYya(0);
|
||||
if (!_hasWanted) return;
|
||||
_hasWanted = false;
|
||||
|
||||
int yFloor = Mth::floor(mob->bb.y0 + 0.5f);
|
||||
|
||||
float xd = wantedX - mob->x;
|
||||
float zd = wantedZ - mob->z;
|
||||
float yd = wantedY - yFloor;
|
||||
float dd = xd * xd + yd * yd + zd * zd;
|
||||
if (dd < MIN_SPEED_SQR) return;
|
||||
|
||||
float yRotD = (float) (std::atan2(zd, xd) * 180 / Mth::PI) - 90;
|
||||
|
||||
mob->yRot = rotlerp(mob->yRot, yRotD, MAX_TURN);
|
||||
mob->setSpeed(speed);
|
||||
|
||||
if (yd > 0 && xd * xd + zd * zd < 1) mob->getJumpControl()->jump();
|
||||
}
|
||||
|
||||
float MoveControl::rotlerp( float a, float b, float max ) {
|
||||
float diff = b - a;
|
||||
while (diff < -180)
|
||||
diff += 360;
|
||||
while (diff >= 180)
|
||||
diff -= 360;
|
||||
if (diff > max) {
|
||||
diff = max;
|
||||
}
|
||||
if (diff < -max) {
|
||||
diff = -max;
|
||||
}
|
||||
return a + diff;
|
||||
}
|
||||
38
src/world/entity/ai/control/MoveControl.h
Executable file
38
src/world/entity/ai/control/MoveControl.h
Executable file
@@ -0,0 +1,38 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__MoveControl_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__MoveControl_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.control;
|
||||
|
||||
#include "Control.h"
|
||||
|
||||
#include "../../Mob.h"
|
||||
#include "../../../../util/Mth.h"
|
||||
|
||||
class MoveControl: public Control
|
||||
{
|
||||
static const float MAX_TURN;
|
||||
public:
|
||||
static const float MIN_SPEED;
|
||||
static const float MIN_SPEED_SQR;
|
||||
|
||||
MoveControl(Mob* mob);
|
||||
|
||||
bool hasWanted();
|
||||
|
||||
float getSpeed();
|
||||
|
||||
void setWantedPosition(float x, float y, float z, float speed);
|
||||
|
||||
void tick();
|
||||
private:
|
||||
float rotlerp(float a, float b, float max);
|
||||
|
||||
Mob* mob;
|
||||
float wantedX;
|
||||
float wantedY;
|
||||
float wantedZ;
|
||||
float speed;
|
||||
bool _hasWanted;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_CONTROL__MoveControl_H__*/
|
||||
57
src/world/entity/ai/goal/BreakDoorGoal.h
Executable file
57
src/world/entity/ai/goal/BreakDoorGoal.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__BreakDoorGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__BreakDoorGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity->ai.goal;
|
||||
|
||||
#include "DoorInteractGoal.h"
|
||||
|
||||
#include "../../Entity.h"
|
||||
#include "../../../level/tile/LevelEvent.h"
|
||||
#include "../../../level/Level.h"
|
||||
#include "../../../level/tile/DoorTile.h"
|
||||
#include "../../../../SharedConstants.h"
|
||||
|
||||
class BreakDoorGoal: public DoorInteractGoal
|
||||
{
|
||||
typedef DoorInteractGoal super;
|
||||
public:
|
||||
BreakDoorGoal(Monster* mob)
|
||||
: super(mob)
|
||||
{}
|
||||
|
||||
bool canUse() {
|
||||
if (!super::canUse()) return false;
|
||||
return !doorTile->isOpen(mob->level, doorX, doorY, doorZ);
|
||||
}
|
||||
|
||||
void start() {
|
||||
super::start();
|
||||
breakTime = SharedConstants::TicksPerSecond * 12;
|
||||
}
|
||||
|
||||
bool canContinueToUse() {
|
||||
float d = mob->distanceToSqr((float)doorX, (float)doorY, (float)doorZ);
|
||||
return breakTime >= 0 && !doorTile->isOpen(mob->level, doorX, doorY, doorZ) && d < 2 * 2;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
super::tick();
|
||||
if (mob->random.nextInt(20) == 0) {
|
||||
//mob->level->levelEvent(LevelEvent::SOUND_ZOMBIE_WOODEN_DOOR, doorX, doorY, doorZ, 0);
|
||||
}
|
||||
|
||||
//LOGI("time: %d\n", breakTime);
|
||||
|
||||
if (--breakTime == 0) {
|
||||
/*if (mob->level->difficulty == Difficulty.HARD)*/ {
|
||||
mob->level->setTile(doorX, doorY, doorZ, 0);
|
||||
//mob->level->levelEvent(LevelEvent::SOUND_ZOMBIE_DOOR_CRASH, doorX, doorY, doorZ, 0);
|
||||
//mob->level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, doorX, doorY, doorZ, doorTile->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
int breakTime;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__BreakDoorGoal_H__*/
|
||||
79
src/world/entity/ai/goal/DoorInteractGoal.h
Executable file
79
src/world/entity/ai/goal/DoorInteractGoal.h
Executable file
@@ -0,0 +1,79 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__DoorInteractGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__DoorInteractGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.goal;
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
#include "../PathNavigation.h"
|
||||
#include "../../monster/Monster.h"
|
||||
#include "../../../level/pathfinder/Path.h"
|
||||
#include "../../../level/tile/DoorTile.h"
|
||||
|
||||
class DoorInteractGoal: public Goal
|
||||
{
|
||||
public:
|
||||
DoorInteractGoal(Monster* mob)
|
||||
: mob(mob)
|
||||
{}
|
||||
|
||||
bool canUse() {
|
||||
if (!mob->horizontalCollision) return false;
|
||||
PathNavigation* pathNav = mob->getNavigation();
|
||||
Path* path = pathNav->getPath();
|
||||
if (path == NULL || path->isDone() || !pathNav->canOpenDoors)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < Mth::Min(path->getIndex() + 2, path->getSize()); ++i) {
|
||||
Node* n = path->get(i);
|
||||
doorX = n->x;
|
||||
doorY = n->y + 1;
|
||||
doorZ = n->z;
|
||||
if (mob->distanceToSqr((float)doorX, mob->y, (float)doorZ) > 1.5f * 1.5f) continue;
|
||||
doorTile = getDoorTile(doorX, doorY, doorZ);
|
||||
if (doorTile == NULL) continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
doorX = Mth::floor(mob->x);
|
||||
doorY = Mth::floor(mob->y + 1);
|
||||
doorZ = Mth::floor(mob->z);
|
||||
doorTile = getDoorTile(doorX, doorY, doorZ);
|
||||
return doorTile != NULL;
|
||||
}
|
||||
|
||||
bool canContinueToUse() {
|
||||
return !passed;
|
||||
}
|
||||
|
||||
void start() {
|
||||
passed = false;
|
||||
doorOpenDirX = doorX + 0.5f - mob->x;
|
||||
doorOpenDirZ = doorZ + 0.5f - mob->z;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
float newDoorDirX = doorX + 0.5f - mob->x;
|
||||
float newDoorDirZ = doorZ + 0.5f - mob->z;
|
||||
float dot = doorOpenDirX * newDoorDirX + doorOpenDirZ * newDoorDirZ;
|
||||
if (dot < 0) {
|
||||
passed = true;
|
||||
}
|
||||
}
|
||||
private:
|
||||
DoorTile* getDoorTile(int x, int y, int z) {
|
||||
int tileId = mob->level->getTile(x, y, z);
|
||||
if (tileId != Tile::door_wood->id) return NULL;
|
||||
DoorTile* doorTile = (DoorTile*) Tile::tiles[tileId];
|
||||
return doorTile;
|
||||
}
|
||||
protected:
|
||||
Monster* mob;
|
||||
int doorX, doorY, doorZ;
|
||||
DoorTile* doorTile;
|
||||
private:
|
||||
bool passed;
|
||||
float doorOpenDirX, doorOpenDirZ;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__DoorInteractGoal_H__*/
|
||||
44
src/world/entity/ai/goal/Goal.h
Executable file
44
src/world/entity/ai/goal/Goal.h
Executable file
@@ -0,0 +1,44 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__Goal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__Goal_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.goal;
|
||||
|
||||
class Goal
|
||||
{
|
||||
public:
|
||||
Goal()
|
||||
: _requiredControlFlags(0)
|
||||
{}
|
||||
virtual ~Goal() {}
|
||||
|
||||
virtual bool canUse() = 0;
|
||||
|
||||
virtual bool canContinueToUse() {
|
||||
return canUse();
|
||||
}
|
||||
|
||||
virtual bool canInterrupt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void start() {
|
||||
}
|
||||
|
||||
virtual void stop() {
|
||||
}
|
||||
|
||||
virtual void tick() {
|
||||
}
|
||||
|
||||
void setRequiredControlFlags(int requiredControlFlags) {
|
||||
_requiredControlFlags = requiredControlFlags;
|
||||
}
|
||||
|
||||
int getRequiredControlFlags() {
|
||||
return _requiredControlFlags;
|
||||
}
|
||||
private:
|
||||
int _requiredControlFlags;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__Goal_H__*/
|
||||
104
src/world/entity/ai/goal/GoalSelector.h
Executable file
104
src/world/entity/ai/goal/GoalSelector.h
Executable file
@@ -0,0 +1,104 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__GoalSelector_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__GoalSelector_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.goal;
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class GoalSelector
|
||||
{
|
||||
class InternalGoal {
|
||||
public:
|
||||
InternalGoal(short prio, Goal* goal)
|
||||
: prio(prio),
|
||||
goal(goal),
|
||||
isUsing(false)
|
||||
{}
|
||||
|
||||
Goal* goal;
|
||||
short prio;
|
||||
bool isUsing;
|
||||
};
|
||||
public:
|
||||
~GoalSelector() {
|
||||
for (unsigned int i = 0; i < goals.size(); ++i) {
|
||||
delete goals[i].goal;
|
||||
}
|
||||
}
|
||||
|
||||
void addGoal(int prio, Goal* goal) {
|
||||
goals.push_back(InternalGoal(prio, goal));
|
||||
}
|
||||
|
||||
void tick() {
|
||||
std::vector<InternalGoal> toStart;
|
||||
|
||||
for (std::vector<InternalGoal>::iterator it = goals.begin(); it != goals.end(); ++it) {
|
||||
InternalGoal& ig = *it;
|
||||
bool isUsing = ig.isUsing; //usingGoals.contains(ig);
|
||||
|
||||
if (isUsing) {
|
||||
if (!canUseInSystem(ig) || !ig.goal->canContinueToUse()) {
|
||||
ig.goal->stop();
|
||||
ig.isUsing = false;
|
||||
//usingGoals.remove(ig);
|
||||
} else continue;
|
||||
}
|
||||
|
||||
if (!canUseInSystem(ig) || !ig.goal->canUse()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toStart.push_back(ig);
|
||||
//usingGoals.add(ig);
|
||||
ig.isUsing = true;
|
||||
}
|
||||
|
||||
//bool debug = false;
|
||||
//if (debug && toStart.size() > 0) printf("Starting: ");
|
||||
for (std::vector<InternalGoal>::iterator it = toStart.begin(); it != toStart.end(); ++it) {
|
||||
InternalGoal& ig = *it;
|
||||
//if (debug) printf(" %s, ", ig.goal.toString() + ", ");
|
||||
ig.goal->start();
|
||||
}
|
||||
|
||||
//if (debug && usingGoals.size() > 0) printf("Running: ");
|
||||
for (std::vector<InternalGoal>::iterator it = goals.begin(); it != goals.end(); ++it) {
|
||||
InternalGoal& ig = *it;
|
||||
if (ig.isUsing) {
|
||||
//if (debug) printf(" %s\n", ig.goal.toString());
|
||||
ig.goal->tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//std::vector<InternalGoal>& getRunningGoals() {
|
||||
// return usingGoals;
|
||||
//}
|
||||
private:
|
||||
bool canUseInSystem(InternalGoal& goal) {
|
||||
for (std::vector<InternalGoal>::iterator it = goals.begin(); it != goals.end(); ++it) {
|
||||
InternalGoal& ig = *it;
|
||||
if (ig.goal == goal.goal && ig.prio == goal.prio)
|
||||
continue;
|
||||
if (goal.prio >= ig.prio) {
|
||||
if (ig.isUsing && !canCoExist(goal, ig))
|
||||
return false;
|
||||
} else if (ig.isUsing && !ig.goal->canInterrupt())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canCoExist(InternalGoal& goalA, InternalGoal& goalB) {
|
||||
return (goalA.goal->getRequiredControlFlags() & goalB.goal->getRequiredControlFlags()) == 0;
|
||||
}
|
||||
|
||||
std::vector<InternalGoal> goals;
|
||||
//std::vector<InternalGoal> usingGoals;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__GoalSelector_H__*/
|
||||
94
src/world/entity/ai/goal/MeleeAttackGoal.h
Executable file
94
src/world/entity/ai/goal/MeleeAttackGoal.h
Executable file
@@ -0,0 +1,94 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__MeleeAttackGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__MeleeAttackGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.goal;
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
#include "../control/Control.h"
|
||||
#include "../../monster/Monster.h"
|
||||
#include "../../../level/Level.h"
|
||||
#include "../../../level/pathfinder/Path.h"
|
||||
#include "../Sensing.h"
|
||||
|
||||
class MeleeAttackGoal: public Goal
|
||||
{
|
||||
public:
|
||||
MeleeAttackGoal(Monster* mob, float speed, bool trackTarget, int attackType = 0)
|
||||
: mob(mob),
|
||||
level(mob->level),
|
||||
speed(speed),
|
||||
trackTarget(trackTarget),
|
||||
attackTime(0),
|
||||
attackType(attackType),
|
||||
path(NULL)
|
||||
{
|
||||
setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag);
|
||||
}
|
||||
~MeleeAttackGoal() {
|
||||
if (path) {
|
||||
LOGI("mag-deleting %p (%d)\n", path, path->id);
|
||||
delete path;
|
||||
}
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
bool canUse() {
|
||||
Mob* bestTarget = mob->getTarget();
|
||||
if (bestTarget == NULL) return false;
|
||||
if (attackType != 0 && !mob->isPlayer()) return false; //!attackType.isAssignableFrom(bestTarget.getClass())) return false;
|
||||
target = bestTarget;
|
||||
if (path) {
|
||||
LOGI("mag-canuse-deleting %p (%d)\n", path, path->id);
|
||||
delete path;
|
||||
}
|
||||
path = mob->getNavigation()->createPath(target);
|
||||
return path != NULL;
|
||||
}
|
||||
|
||||
bool canContinueToUse() {
|
||||
Mob* bestTarget = mob->getTarget();
|
||||
if (bestTarget == NULL) return false;
|
||||
if (attackType != 0 && !mob->isPlayer()) return false;//!attackType.isAssignableFrom(bestTarget.getClass())) return false;
|
||||
target = bestTarget;
|
||||
if (!trackTarget) return !mob->getNavigation()->isDone();
|
||||
return true;
|
||||
}
|
||||
|
||||
void start() {
|
||||
mob->getNavigation()->moveTo(path, speed, false);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
target = NULL;
|
||||
mob->getNavigation()->stop();
|
||||
}
|
||||
|
||||
void tick() {
|
||||
//mob->getLookControl().setLookAt(target, 30, 30);
|
||||
if (trackTarget || mob->sensing->canSee(target)) {
|
||||
//LOGI("target: %p @ %f, %f, %f\n", target, target->x, target->y, target->z);
|
||||
mob->getNavigation()->moveTo(target, speed);
|
||||
}
|
||||
|
||||
attackTime = Mth::Max(attackTime - 1, 0);
|
||||
|
||||
float meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2);
|
||||
if (mob->distanceToSqr(target->x, target->bb.y0, target->z) > meleeRadiusSqr) return;
|
||||
if (attackTime > 0) return;
|
||||
attackTime = 20;
|
||||
mob->doHurtTarget(target);
|
||||
}
|
||||
|
||||
private:
|
||||
Level* level;
|
||||
Monster* mob;
|
||||
Mob* target;
|
||||
int attackTime;
|
||||
float speed;
|
||||
Path* path;
|
||||
int attackType;
|
||||
bool trackTarget;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__MeleeAttackGoal_H__*/
|
||||
54
src/world/entity/ai/goal/RandomStrollGoal.h
Executable file
54
src/world/entity/ai/goal/RandomStrollGoal.h
Executable file
@@ -0,0 +1,54 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__RandomStrollGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__RandomStrollGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.goal;
|
||||
|
||||
#include "Goal.h"
|
||||
|
||||
#include "../../../../SharedConstants.h"
|
||||
#include "../../PathfinderMob.h"
|
||||
#include "../control/Control.h"
|
||||
#include "../util/RandomPos.h"
|
||||
#include "../../../phys/Vec3.h"
|
||||
#include "../util/RandomPos.h"
|
||||
|
||||
class RandomStrollGoal: public Goal
|
||||
{
|
||||
public:
|
||||
RandomStrollGoal(PathfinderMob* mob, float speed)
|
||||
: mob(mob),
|
||||
speed(speed)
|
||||
{
|
||||
setRequiredControlFlags(Control::MoveControlFlag);
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
bool canUse() {
|
||||
if (mob->getNoActionTime() >= SharedConstants::TicksPerSecond * 5) return false;
|
||||
if (mob->random.nextInt(120) != 0) return false;
|
||||
|
||||
Vec3 pos;
|
||||
if (!RandomPos::getPos(pos, mob, 10, 7)) return false;
|
||||
wantedX = pos.x;
|
||||
wantedY = pos.y;
|
||||
wantedZ = pos.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
bool canContinueToUse() {
|
||||
return !mob->getNavigation()->isDone();
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
void start() {
|
||||
mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed);
|
||||
}
|
||||
|
||||
private:
|
||||
PathfinderMob* mob;
|
||||
float wantedX, wantedY, wantedZ;
|
||||
float speed;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL__RandomStrollGoal_H__*/
|
||||
41
src/world/entity/ai/goal/target/HurtByTargetGoal.h
Executable file
41
src/world/entity/ai/goal/target/HurtByTargetGoal.h
Executable file
@@ -0,0 +1,41 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__HurtByTargetGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__HurtByTargetGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity->ai.goal.target;
|
||||
|
||||
#include "TargetGoal.h"
|
||||
#include "../../../../phys/AABB.h"
|
||||
|
||||
class HurtByTargetGoal: public TargetGoal
|
||||
{
|
||||
typedef TargetGoal super;
|
||||
public:
|
||||
HurtByTargetGoal(Monster* mob, bool alertSameType)
|
||||
: super(mob, 16, false),
|
||||
alertSameType(alertSameType)
|
||||
{
|
||||
setRequiredControlFlags(TargetGoal::TargetFlag);
|
||||
}
|
||||
|
||||
bool canUse() {
|
||||
return canAttack(mob->getLastHurtByMob(), true);
|
||||
}
|
||||
|
||||
void start() {
|
||||
mob->setTarget(mob->getLastHurtByMob());
|
||||
|
||||
// if (alertSameType) {
|
||||
// List<Entity> nearby = mob.level->getEntitiesOfClass(mob.getClass(), AABB.newTemp(mob.x, mob.y, mob.z, mob.x + 1, mob.y + 1, mob.z + 1).grow(within, 4, within));
|
||||
// for (Entity* ent : nearby) {
|
||||
// Mob other = (Mob) ent;
|
||||
// if (this->mob == other) continue;
|
||||
// if (other.getTarget() != NULL) continue;
|
||||
// other.setTarget(mob.getLastHurtByMob());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
private:
|
||||
bool alertSameType;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__HurtByTargetGoal_H__*/
|
||||
42
src/world/entity/ai/goal/target/NearestAttackableTargetGoal.h
Executable file
42
src/world/entity/ai/goal/target/NearestAttackableTargetGoal.h
Executable file
@@ -0,0 +1,42 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__NearestAttackableTargetGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__NearestAttackableTargetGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity->ai.goal.target;
|
||||
|
||||
/* import net.minecraft.world.entity->* */
|
||||
#include "TargetGoal.h"
|
||||
#include "../../../player/Player.h"
|
||||
|
||||
|
||||
class NearestAttackableTargetGoal: public TargetGoal
|
||||
{
|
||||
typedef TargetGoal super;
|
||||
public:
|
||||
NearestAttackableTargetGoal(Monster* mob, int targetType, float within, int randomInterval, bool mustSee)
|
||||
: super(mob, within, mustSee),
|
||||
targetType(targetType),
|
||||
randomInterval(randomInterval)
|
||||
{
|
||||
setRequiredControlFlags(TargetGoal::TargetFlag);
|
||||
}
|
||||
|
||||
bool canUse() {
|
||||
if (randomInterval > 0 && mob->random.nextInt(randomInterval) != 0) return false;
|
||||
Mob* potentialTarget = NULL;
|
||||
if (targetType == 1) potentialTarget = mob->level->getNearestPlayer(mob, within); //@todo: targetType
|
||||
//else potentialTarget = (Mob*) mob->level->getClosestEntityOfClass(targetType, mob->bb.grow(within, 4, within), mob);
|
||||
if (!canAttack(potentialTarget, false)) return false;
|
||||
target = potentialTarget;
|
||||
return true;
|
||||
}
|
||||
|
||||
void start() {
|
||||
mob->setTarget(target);
|
||||
}
|
||||
private:
|
||||
Mob* target;
|
||||
int targetType;
|
||||
int randomInterval;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__NearestAttackableTargetGoal_H__*/
|
||||
57
src/world/entity/ai/goal/target/TargetGoal.h
Executable file
57
src/world/entity/ai/goal/target/TargetGoal.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__TargetGoal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__TargetGoal_H__
|
||||
|
||||
//package net.minecraft.world.entity->ai.goal.target;
|
||||
|
||||
/* import net.minecraft.world.entity->* */
|
||||
#include "../Goal.h"
|
||||
/* import net.minecraft.world.entity->monster.* */
|
||||
#include "../../../player/Player.h"
|
||||
|
||||
class Monster;
|
||||
|
||||
class TargetGoal: public Goal
|
||||
{
|
||||
public:
|
||||
static const int TargetFlag = 1;
|
||||
|
||||
TargetGoal(Monster* mob, float within, bool mustSee)
|
||||
: mob(mob),
|
||||
within(within),
|
||||
mustSee(mustSee)
|
||||
{}
|
||||
|
||||
bool canContinueToUse() {
|
||||
Mob* target = mob->getTarget();
|
||||
if (target == NULL) return false;
|
||||
if (!target->isAlive()) return false;
|
||||
if (mob->distanceToSqr(target) > within * within) return false;
|
||||
if (mustSee && !mob->sensing->canSee(target)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
mob->setTarget(NULL);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool canAttack(Mob* target, bool allowInvulnerable) {
|
||||
if (target == NULL) return false;
|
||||
if (target == mob) return false;
|
||||
if (!target->isAlive()) return false;
|
||||
if (target->bb.y1 <= mob->bb.y0 || target->bb.y0 >= mob->bb.y1) return false;
|
||||
//if (target instanceof Creeper || target instanceof Ghast) return false;
|
||||
|
||||
if (target->isPlayer()) {
|
||||
if (!allowInvulnerable && ((Player*) target)->abilities.invulnerable) return false;
|
||||
}
|
||||
if (mustSee && !mob->sensing->canSee(target)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
Monster* mob;
|
||||
float within;
|
||||
bool mustSee;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_GOAL_TARGET__TargetGoal_H__*/
|
||||
71
src/world/entity/ai/util/RandomPos.h
Executable file
71
src/world/entity/ai/util/RandomPos.h
Executable file
@@ -0,0 +1,71 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_AI_UTIL__RandomPos_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_AI_UTIL__RandomPos_H__
|
||||
|
||||
//package net.minecraft.world.entity.ai.util;
|
||||
|
||||
#include "../../PathfinderMob.h"
|
||||
#include "../../../phys/Vec3.h"
|
||||
|
||||
class RandomPos
|
||||
{
|
||||
public:
|
||||
static bool getPos(Vec3& outPos, PathfinderMob* mob, int xzDist, int yDist) {
|
||||
return generateRandomPos(outPos, mob, xzDist, yDist, NULL);
|
||||
}
|
||||
|
||||
static bool getPosTowards(Vec3& outPos, PathfinderMob* mob, int xzDist, int yDist, Vec3* towardsPos) {
|
||||
Vec3 tempDir(towardsPos->x, towardsPos->y, towardsPos->z);
|
||||
tempDir.subSelf(mob->x, mob->y, mob->z);
|
||||
return generateRandomPos(outPos, mob, xzDist, yDist, &tempDir);
|
||||
}
|
||||
|
||||
static bool getPosAvoid(Vec3& outPos, PathfinderMob* mob, int xzDist, int yDist, Vec3* avoidPos) {
|
||||
Vec3 tempDir(mob->x, mob->y, mob->z);
|
||||
tempDir.subSelf(avoidPos->x, avoidPos->y, avoidPos->z);
|
||||
return generateRandomPos(outPos, mob, xzDist, yDist, &tempDir);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool generateRandomPos(Vec3& outPos, PathfinderMob* mob, int xzDist, int yDist, Vec3* dir) {
|
||||
Random& random = mob->random;
|
||||
bool hasBest = false;
|
||||
int xBest = 0, yBest = 0, zBest = 0;
|
||||
float best = -99999;
|
||||
|
||||
// bool restrict;
|
||||
// if (mob->hasRestriction()) {
|
||||
// float restDist = mob->getRestrictCenter().dist((int) Math.floor(mob->x), (int) Math.floor(mob->y), (int) Math.floor(mob->z)) + 4;
|
||||
// restrict = restDist < mob->getRestrictRadius() + xzDist;
|
||||
// } else restrict = false;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int xt = random.nextInt(2 * xzDist) - xzDist;
|
||||
int yt = random.nextInt(2 * yDist) - yDist;
|
||||
int zt = random.nextInt(2 * xzDist) - xzDist;
|
||||
|
||||
if (dir != NULL && xt * dir->x + zt * dir->z < 0) continue;
|
||||
|
||||
xt += Mth::floor(mob->x);
|
||||
yt += Mth::floor(mob->y);
|
||||
zt += Mth::floor(mob->z);
|
||||
|
||||
//if (restrict && !mob->isWithinRestriction(xt, yt, zt)) continue;
|
||||
float value = mob->getWalkTargetValue(xt, yt, zt);
|
||||
if (value > best) {
|
||||
best = value;
|
||||
xBest = xt;
|
||||
yBest = yt;
|
||||
zBest = zt;
|
||||
hasBest = true;
|
||||
}
|
||||
}
|
||||
if (hasBest) {
|
||||
outPos.set((float)xBest, (float)yBest, (float)zBest);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_AI_UTIL__RandomPos_H__*/
|
||||
92
src/world/entity/animal/Animal.cpp
Executable file
92
src/world/entity/animal/Animal.cpp
Executable file
@@ -0,0 +1,92 @@
|
||||
#include "Animal.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../level/tile/Tile.h"
|
||||
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
|
||||
Animal::Animal( Level* level )
|
||||
: super(level),
|
||||
inLove(0)
|
||||
{
|
||||
//entityData.define(DATA_AGE_ID, (SynchedEntityData::TypeInt)0);
|
||||
}
|
||||
|
||||
bool Animal::hurt( Entity* source, int dmg )
|
||||
{
|
||||
fleeTime = 3 * SharedConstants::TicksPerSecond;
|
||||
attackTargetId = 0;
|
||||
inLove = 0;
|
||||
return super::hurt(source, dmg);
|
||||
}
|
||||
|
||||
bool Animal::canSpawn()
|
||||
{
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(bb.y0);
|
||||
int zt = Mth::floor(z);
|
||||
return level->getTile(xt, yt - 1, zt) == ((Tile*)Tile::grass)->id && level->getRawBrightness(xt, yt, zt) > 8 && super::canSpawn();
|
||||
}
|
||||
|
||||
int Animal::getAmbientSoundInterval()
|
||||
{
|
||||
return 12 * SharedConstants::TicksPerSecond;
|
||||
}
|
||||
|
||||
float Animal::getWalkTargetValue( int x, int y, int z )
|
||||
{
|
||||
if (level->getTile(x, y - 1, z) == ((Tile*)Tile::grass)->id) return 10;
|
||||
return level->getBrightness(x, y, z) - 0.5f;
|
||||
}
|
||||
|
||||
Entity* Animal::findAttackTarget()
|
||||
{
|
||||
return NULL;
|
||||
|
||||
//if (fleeTime > 0)
|
||||
// return NULL;
|
||||
|
||||
//int inLove = -1;
|
||||
|
||||
//float r = 8;
|
||||
//if (inLove > 0) {
|
||||
// EntityList others;
|
||||
// level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others);
|
||||
// for (unsigned int i = 0; i < others.size(); i++) {
|
||||
// Animal* p = (Animal*) others[i];
|
||||
// if (p != this && p->inLove > 0) {
|
||||
// return p;
|
||||
// }
|
||||
// }
|
||||
//} else {
|
||||
// /* if (getAge() == 0) {
|
||||
// List<Entity> players = level.getEntitiesOfClass(Player.class, bb.expand(r, r, r));
|
||||
// for (int i = 0; i < players.size(); i++) {
|
||||
// Player p = (Player) players.get(i);
|
||||
// if (p.getSelectedItem() != null && this.isFood(p.getSelectedItem())) {
|
||||
// return p;
|
||||
// }
|
||||
// }
|
||||
// } else if (getAge() > 0) {
|
||||
// EntityList others;
|
||||
// level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others);
|
||||
// for (unsigned int i = 0; i < others.size(); i++) {
|
||||
// Animal* p = (Animal*) others[i];
|
||||
// if (p != this && p->getAge() < 0) {
|
||||
// return p;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// */
|
||||
//}
|
||||
//return NULL;
|
||||
}
|
||||
|
||||
bool Animal::removeWhenFarAway()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int Animal::getCreatureBaseType() const {
|
||||
return MobTypes::BaseCreature;
|
||||
}
|
||||
39
src/world/entity/animal/Animal.h
Executable file
39
src/world/entity/animal/Animal.h
Executable file
@@ -0,0 +1,39 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Animal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Animal_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "../AgableMob.h"
|
||||
#include "../Creature.h"
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
class CompoundTag;
|
||||
|
||||
class Animal: public AgableMob,
|
||||
public Creature
|
||||
{
|
||||
typedef AgableMob super;
|
||||
|
||||
public:
|
||||
Animal(Level* level);
|
||||
|
||||
//@Override
|
||||
bool hurt(Entity* source, int dmg);
|
||||
|
||||
bool canSpawn();
|
||||
|
||||
int getAmbientSoundInterval();
|
||||
|
||||
int getCreatureBaseType() const;
|
||||
|
||||
bool removeWhenFarAway();
|
||||
|
||||
protected:
|
||||
float getWalkTargetValue(int x, int y, int z);
|
||||
Entity* findAttackTarget();
|
||||
private:
|
||||
int inLove;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Animal_H__*/
|
||||
10
src/world/entity/animal/AnimalInclude.h
Executable file
10
src/world/entity/animal/AnimalInclude.h
Executable file
@@ -0,0 +1,10 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__AnimalInclude_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__AnimalInclude_H__
|
||||
|
||||
#include "Animal.h"
|
||||
#include "Chicken.h"
|
||||
#include "Cow.h"
|
||||
#include "Pig.h"
|
||||
#include "Sheep.h"
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__AnimalInclude_H__*/
|
||||
113
src/world/entity/animal/Chicken.cpp
Executable file
113
src/world/entity/animal/Chicken.cpp
Executable file
@@ -0,0 +1,113 @@
|
||||
#include "Chicken.h"
|
||||
#include "../../item/Item.h"
|
||||
#include "../../level/Level.h"
|
||||
|
||||
Chicken::Chicken( Level* level )
|
||||
: super(level),
|
||||
sheared(false),
|
||||
flap(0),
|
||||
oFlap(0),
|
||||
flapSpeed(0),
|
||||
oFlapSpeed(0),
|
||||
flapping(1),
|
||||
eggTime(0)
|
||||
{
|
||||
entityRendererId = ER_CHICKEN_RENDERER;
|
||||
|
||||
textureName = "mob/chicken.png";
|
||||
setSize(0.3f, 0.7f);
|
||||
eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5;
|
||||
}
|
||||
|
||||
int Chicken::getEntityTypeId() const
|
||||
{
|
||||
return MobTypes::Chicken;
|
||||
}
|
||||
|
||||
|
||||
int Chicken::getMaxHealth()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
void Chicken::aiStep()
|
||||
{
|
||||
super::aiStep();
|
||||
|
||||
oFlap = flap;
|
||||
oFlapSpeed = flapSpeed;
|
||||
|
||||
flapSpeed += (onGround ? -1 : 4) * 0.3f;
|
||||
if (flapSpeed < 0) flapSpeed = 0;
|
||||
if (flapSpeed > 1) flapSpeed = 1;
|
||||
|
||||
if (!onGround && flapping < 1) flapping = 1;
|
||||
flapping *= 0.9f;
|
||||
|
||||
if (!onGround && yd < 0) {
|
||||
yd *= 0.6f;
|
||||
}
|
||||
|
||||
flap += flapping * 2;
|
||||
|
||||
//@todo
|
||||
//if (!isBaby()) {
|
||||
// if (!level->isClientSide && --eggTime <= 0) {
|
||||
// level->playSound(this, "mob.chickenplop", 1.0f, (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f);
|
||||
// spawnAtLocation(Item::egg->id, 1);
|
||||
// eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
void Chicken::addAdditonalSaveData( CompoundTag* tag )
|
||||
{
|
||||
super::addAdditonalSaveData(tag);
|
||||
}
|
||||
|
||||
void Chicken::readAdditionalSaveData( CompoundTag* tag )
|
||||
{
|
||||
super::readAdditionalSaveData(tag);
|
||||
}
|
||||
|
||||
void Chicken::causeFallDamage( float distance )
|
||||
{
|
||||
}
|
||||
|
||||
const char* Chicken::getAmbientSound()
|
||||
{
|
||||
return "mob.chicken";
|
||||
}
|
||||
|
||||
std::string Chicken::getHurtSound()
|
||||
{
|
||||
return "mob.chickenhurt";
|
||||
}
|
||||
|
||||
std::string Chicken::getDeathSound()
|
||||
{
|
||||
return "mob.chickenhurt";
|
||||
}
|
||||
|
||||
//int Chicken::getDeathLoot()
|
||||
//{
|
||||
// return Item::feather->id;
|
||||
//}
|
||||
|
||||
void Chicken::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ )
|
||||
{
|
||||
//// drop some feathers
|
||||
int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel);
|
||||
for (int i = 0; i < count; i++) {
|
||||
spawnAtLocation(Item::feather->id, 1);
|
||||
}
|
||||
//// and some meat
|
||||
//if (isOnFire()) spawnAtLocation(Item::chicken_cooked->id, 1); //@fire
|
||||
//else
|
||||
spawnAtLocation(Item::chicken_raw->id, 1);
|
||||
}
|
||||
|
||||
Animal* Chicken::getBreedOffspring( Animal* target )
|
||||
{
|
||||
return new Chicken(level);
|
||||
}
|
||||
49
src/world/entity/animal/Chicken.h
Executable file
49
src/world/entity/animal/Chicken.h
Executable file
@@ -0,0 +1,49 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Chicken_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Chicken_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "Animal.h"
|
||||
|
||||
class CompoundTag;
|
||||
class Level;
|
||||
|
||||
class Chicken: public Animal
|
||||
{
|
||||
typedef Animal super;
|
||||
public:
|
||||
Chicken(Level* level);
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
void aiStep();
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
protected:
|
||||
void causeFallDamage(float distance);
|
||||
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
//int getDeathLoot();
|
||||
|
||||
//@Override
|
||||
void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/);
|
||||
|
||||
//@Override
|
||||
Animal* getBreedOffspring(Animal* target);
|
||||
public:
|
||||
bool sheared;
|
||||
float flap;
|
||||
float flapSpeed;
|
||||
float oFlapSpeed, oFlap;
|
||||
float flapping;
|
||||
int eggTime;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Chicken_H__*/
|
||||
79
src/world/entity/animal/Cow.cpp
Executable file
79
src/world/entity/animal/Cow.cpp
Executable file
@@ -0,0 +1,79 @@
|
||||
#include "Cow.h"
|
||||
#include "../player/Player.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../item/Item.h"
|
||||
|
||||
Cow::Cow( Level* level )
|
||||
: super(level)
|
||||
{
|
||||
entityRendererId = ER_COW_RENDERER;
|
||||
|
||||
textureName = "mob/cow.png";
|
||||
setSize(0.9f, 1.3f);
|
||||
}
|
||||
|
||||
int Cow::getEntityTypeId() const {
|
||||
return MobTypes::Cow;
|
||||
}
|
||||
|
||||
int Cow::getMaxHealth() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
void Cow::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
super::addAdditonalSaveData(tag);
|
||||
}
|
||||
|
||||
void Cow::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
super::readAdditionalSaveData(tag);
|
||||
}
|
||||
|
||||
bool Cow::interact( Player* player ) {
|
||||
//ItemInstance item = player->inventory.getSelected();
|
||||
//if (item != NULL && item.id == Item::bucket_empty->id) {
|
||||
// player->inventory.setItem(player->inventory.selected, /*new*/ ItemInstance(Item::milk));
|
||||
// return true;
|
||||
//}
|
||||
return super::interact(player);
|
||||
}
|
||||
|
||||
const char* Cow::getAmbientSound() {
|
||||
return "mob.cow";
|
||||
}
|
||||
|
||||
std::string Cow::getHurtSound() {
|
||||
return "mob.cowhurt";
|
||||
}
|
||||
|
||||
std::string Cow::getDeathSound() {
|
||||
return "mob.cowhurt";
|
||||
}
|
||||
|
||||
float Cow::getSoundVolume() {
|
||||
return 0.4f;
|
||||
}
|
||||
|
||||
int Cow::getDeathLoot() {
|
||||
return Item::leather->id;
|
||||
}
|
||||
|
||||
void Cow::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) {
|
||||
// drop some leather
|
||||
int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel);
|
||||
for (int i = 0; i < count; i++) {
|
||||
spawnAtLocation(Item::leather->id, 1);
|
||||
}
|
||||
// and some meat
|
||||
count = random.nextInt(3) + 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
// if (isOnFire()) { //@fire
|
||||
// spawnAtLocation(Item::beef_cooked->id, 1);
|
||||
// } else {
|
||||
spawnAtLocation(Item::beef_raw->id, 1);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
Animal* Cow::getBreedOffspring( Animal* target ) {
|
||||
return new Cow(level);
|
||||
}
|
||||
42
src/world/entity/animal/Cow.h
Executable file
42
src/world/entity/animal/Cow.h
Executable file
@@ -0,0 +1,42 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Cow_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Cow_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "Animal.h"
|
||||
|
||||
class Level;
|
||||
class Player;
|
||||
class CompoundTag;
|
||||
|
||||
class Cow: public Animal
|
||||
{
|
||||
typedef Animal super;
|
||||
public:
|
||||
Cow(Level* level);
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
bool interact(Player* player);
|
||||
protected:
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
float getSoundVolume();
|
||||
|
||||
int getDeathLoot();
|
||||
/*@Override*/
|
||||
void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/);
|
||||
|
||||
/*@Override*/
|
||||
Animal* getBreedOffspring(Animal* target);
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Cow_H__*/
|
||||
70
src/world/entity/animal/Pig.cpp
Executable file
70
src/world/entity/animal/Pig.cpp
Executable file
@@ -0,0 +1,70 @@
|
||||
#include "Pig.h"
|
||||
#include "../player/Player.h"
|
||||
|
||||
Pig::Pig( Level* level ) : super(level)
|
||||
{
|
||||
entityRendererId = ER_PIG_RENDERER;
|
||||
|
||||
textureName = "mob/pig.png";
|
||||
setSize(0.9f, 0.9f);
|
||||
|
||||
//entityData.define(DATA_SADDLE_ID, (SynchedEntityData::TypeChar) 0);
|
||||
}
|
||||
|
||||
int Pig::getEntityTypeId() const
|
||||
{
|
||||
return MobTypes::Pig;
|
||||
}
|
||||
|
||||
bool Pig::interact( Player* player )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Pig::hasSaddle()
|
||||
{
|
||||
return false;
|
||||
//return (entityData.getByte(DATA_SADDLE_ID) & 1) != 0;
|
||||
}
|
||||
|
||||
void Pig::setSaddle( bool value )
|
||||
{
|
||||
//if (value) {
|
||||
// entityData.set(DATA_SADDLE_ID, (char) 1);
|
||||
//} else {
|
||||
// entityData.set(DATA_SADDLE_ID, (char) 0);
|
||||
//}
|
||||
}
|
||||
|
||||
const char* Pig::getAmbientSound()
|
||||
{
|
||||
return "mob.pig";
|
||||
}
|
||||
|
||||
std::string Pig::getHurtSound()
|
||||
{
|
||||
return "mob.pig";
|
||||
}
|
||||
|
||||
std::string Pig::getDeathSound()
|
||||
{
|
||||
return "mob.pigdeath";
|
||||
}
|
||||
|
||||
int Pig::getDeathLoot()
|
||||
{
|
||||
//@fire
|
||||
//if (isOnFire())
|
||||
// return Item::porkChop_cooked->id;
|
||||
return Item::porkChop_raw->id;
|
||||
}
|
||||
|
||||
Animal* Pig::getBreedOffspring( Animal* target )
|
||||
{
|
||||
return new Pig(level);
|
||||
}
|
||||
|
||||
int Pig::getMaxHealth()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
48
src/world/entity/animal/Pig.h
Executable file
48
src/world/entity/animal/Pig.h
Executable file
@@ -0,0 +1,48 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Pig_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Pig_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "Animal.h"
|
||||
|
||||
class Player;
|
||||
|
||||
class Pig: public Animal
|
||||
{
|
||||
typedef Animal super;
|
||||
static const int DATA_SADDLE_ID = 16;
|
||||
|
||||
public:
|
||||
Pig(Level* level);
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
//void addAdditonalSaveData(CompoundTag* tag) {
|
||||
// super::addAdditonalSaveData(tag);
|
||||
// tag->putBoolean("Saddle", hasSaddle());
|
||||
//}
|
||||
|
||||
//void readAdditionalSaveData(CompoundTag* tag) {
|
||||
// super::readAdditionalSaveData(tag);
|
||||
// setSaddle(tag->getBoolean("Saddle"));
|
||||
//}
|
||||
|
||||
bool interact(Player* player);
|
||||
|
||||
int getMaxHealth();
|
||||
|
||||
bool hasSaddle();
|
||||
void setSaddle(bool value);
|
||||
|
||||
protected:
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
int getDeathLoot();
|
||||
|
||||
//@Override
|
||||
Animal* getBreedOffspring(Animal* target);
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Pig_H__*/
|
||||
252
src/world/entity/animal/Sheep.cpp
Executable file
252
src/world/entity/animal/Sheep.cpp
Executable file
@@ -0,0 +1,252 @@
|
||||
#include "Sheep.h"
|
||||
#include "../../item/DyePowderItem.h"
|
||||
#include "../../level/tile/LevelEvent.h"
|
||||
|
||||
const float Sheep::COLOR[][3] = {
|
||||
{ 1.0f, 1.0f, 1.0f }, // white
|
||||
{ 0.95f, 0.7f, 0.2f }, // orange
|
||||
{ 0.9f, 0.5f, 0.85f }, // magenta
|
||||
{ 0.6f, 0.7f, 0.95f }, // light blue
|
||||
{ 0.9f, 0.9f, 0.2f }, // yellow
|
||||
{ 0.5f, 0.8f, 0.1f }, // light green
|
||||
{ 0.95f, 0.7f, 0.8f }, // pink
|
||||
{ 0.3f, 0.3f, 0.3f }, // gray
|
||||
{ 0.6f, 0.6f, 0.6f }, // silver
|
||||
{ 0.3f, 0.6f, 0.7f }, // cyan
|
||||
{ 0.7f, 0.4f, 0.9f }, // purple
|
||||
{ 0.2f, 0.4f, 0.8f }, // blue
|
||||
{ 0.5f, 0.4f, 0.3f }, // brown
|
||||
{ 0.4f, 0.5f, 0.2f }, // green
|
||||
{ 0.8f, 0.3f, 0.3f }, // red
|
||||
{ 0.1f, 0.1f, 0.1f }, // black
|
||||
};
|
||||
const int Sheep::NumColors = sizeof(Sheep::COLOR) / sizeof(Sheep*);
|
||||
|
||||
|
||||
Sheep::Sheep( Level* level )
|
||||
: super(level),
|
||||
eatAnimationTick(0)
|
||||
{
|
||||
entityRendererId = ER_SHEEP_RENDERER;
|
||||
|
||||
this->textureName = "mob/sheep.png";
|
||||
this->setSize(0.9f, 1.3f);
|
||||
|
||||
// sheared and color share a char
|
||||
entityData.define(DATA_WOOL_ID, (SynchedEntityData::TypeChar) 0);
|
||||
}
|
||||
|
||||
int Sheep::getMaxHealth()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
void Sheep::aiStep()
|
||||
{
|
||||
super::aiStep();
|
||||
|
||||
if (eatAnimationTick > 0) {
|
||||
eatAnimationTick--;
|
||||
}
|
||||
}
|
||||
|
||||
void Sheep::handleEntityEvent( char id )
|
||||
{
|
||||
if (id == EntityEvent::EAT_GRASS) {
|
||||
eatAnimationTick = EAT_ANIMATION_TICKS;
|
||||
} else {
|
||||
super::handleEntityEvent(id);
|
||||
}
|
||||
}
|
||||
|
||||
float Sheep::getHeadEatPositionScale( float a )
|
||||
{
|
||||
if (eatAnimationTick <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (eatAnimationTick >= 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) {
|
||||
return 1;
|
||||
}
|
||||
if (eatAnimationTick < 4) {
|
||||
return ((float) eatAnimationTick - a) / 4.f;
|
||||
}
|
||||
return -((float) (eatAnimationTick - EAT_ANIMATION_TICKS) - a) / 4.f;
|
||||
}
|
||||
|
||||
float Sheep::getHeadEatAngleScale( float a )
|
||||
{
|
||||
if (eatAnimationTick > 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) {
|
||||
float scale = ((float) (eatAnimationTick - 4) - a) / (float) (EAT_ANIMATION_TICKS - 8);
|
||||
return Mth::PI * .20f + Mth::PI * .07f * Mth::sin(scale * 28.7f);
|
||||
}
|
||||
if (eatAnimationTick > 0) {
|
||||
return Mth::PI * .20f;
|
||||
}
|
||||
return ((xRot / (float) (180 / Mth::PI)));
|
||||
}
|
||||
|
||||
bool Sheep::interact( Player* player )
|
||||
{
|
||||
ItemInstance* item = player->inventory->getSelected();
|
||||
if (item && item->id == ((Item*)Item::shears)->id && !isSheared() && !isBaby()) {
|
||||
if (!level->isClientSide) {
|
||||
setSheared(true);
|
||||
int count = 1 + random.nextInt(3);
|
||||
for (int i = 0; i < count; i++) {
|
||||
ItemEntity* ie = spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 1);
|
||||
ie->yd += random.nextFloat() * 0.05f;
|
||||
ie->xd += (random.nextFloat() - random.nextFloat()) * 0.1f;
|
||||
ie->zd += (random.nextFloat() - random.nextFloat()) * 0.1f;
|
||||
}
|
||||
}
|
||||
item->hurt(1);
|
||||
}
|
||||
|
||||
return super::interact(player);
|
||||
}
|
||||
|
||||
void Sheep::addAdditonalSaveData( CompoundTag* tag )
|
||||
{
|
||||
super::addAdditonalSaveData(tag);
|
||||
tag->putBoolean("Sheared", isSheared());
|
||||
tag->putByte("Color", (char) getColor());
|
||||
}
|
||||
|
||||
void Sheep::readAdditionalSaveData( CompoundTag* tag )
|
||||
{
|
||||
super::readAdditionalSaveData(tag);
|
||||
setSheared(tag->getBoolean("Sheared"));
|
||||
setColor((int) tag->getByte("Color"));
|
||||
}
|
||||
|
||||
int Sheep::getColor() const
|
||||
{
|
||||
return (int) (entityData.getByte(DATA_WOOL_ID) & 0x0f);
|
||||
}
|
||||
|
||||
void Sheep::setColor( int color )
|
||||
{
|
||||
char current = entityData.getByte(DATA_WOOL_ID);
|
||||
entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) ((current & 0xf0) | (color & 0x0f)));
|
||||
}
|
||||
|
||||
bool Sheep::isSheared() const
|
||||
{
|
||||
return (entityData.getByte(DATA_WOOL_ID) & 0x10) != 0;
|
||||
}
|
||||
|
||||
void Sheep::setSheared( bool value )
|
||||
{
|
||||
char current = entityData.getByte(DATA_WOOL_ID);
|
||||
if (value) {
|
||||
entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current | 0x10));
|
||||
} else {
|
||||
entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current & ~0x10));
|
||||
}
|
||||
}
|
||||
|
||||
int Sheep::getSheepColor( Random* random )
|
||||
{
|
||||
int nextInt = random->nextInt(100);
|
||||
if (nextInt < 5)
|
||||
return 15 - DyePowderItem::BLACK;
|
||||
if (nextInt < 10)
|
||||
return 15 - DyePowderItem::GRAY;
|
||||
if (nextInt < 15)
|
||||
return 15 - DyePowderItem::SILVER;
|
||||
if (nextInt < 18)
|
||||
return 15 - DyePowderItem::BROWN;
|
||||
|
||||
if (random->nextInt(500) == 0)
|
||||
return 15 - DyePowderItem::PINK;
|
||||
|
||||
return 0; // white
|
||||
}
|
||||
|
||||
int Sheep::getEntityTypeId() const
|
||||
{
|
||||
return MobTypes::Sheep;
|
||||
}
|
||||
|
||||
void Sheep::dropDeathLoot(/* bool wasKilledByPlayer, int playerBonusLevel*/ )
|
||||
{
|
||||
if (!isSheared()) {
|
||||
// killing a non-sheared sheep will drop a single block of cloth
|
||||
spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
int Sheep::getDeathLoot()
|
||||
{
|
||||
return Tile::cloth->id;
|
||||
}
|
||||
|
||||
void Sheep::jumpFromGround()
|
||||
{
|
||||
if (eatAnimationTick <= 0) {
|
||||
super::jumpFromGround();
|
||||
}
|
||||
}
|
||||
|
||||
void Sheep::updateAi()
|
||||
{
|
||||
super::updateAi();
|
||||
|
||||
if (!isPathFinding() && eatAnimationTick <= 0 && ((isBaby() && random.nextInt(50) == 0) || random.nextInt(1000) == 0)) {
|
||||
|
||||
int xx = Mth::floor(x);
|
||||
int yy = Mth::floor(y);
|
||||
int zz = Mth::floor(z);
|
||||
|
||||
if (/*(level->getTile(xx, yy, zz) == Tile::tallgrass->id && level->getData(xx, yy, zz) == TallGrass::TALL_GRASS) || */ level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) {
|
||||
eatAnimationTick = EAT_ANIMATION_TICKS;
|
||||
level->broadcastEntityEvent(this, EntityEvent::EAT_GRASS);
|
||||
}
|
||||
} else if (eatAnimationTick == 4) {
|
||||
int xx = Mth::floor(x);
|
||||
int yy = Mth::floor(y);
|
||||
int zz = Mth::floor(z);
|
||||
|
||||
bool ate = false;
|
||||
/* if (level->getTile(xx, yy, zz) == Tile::tallgrass->id) {
|
||||
level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy, zz, Tile::tallgrass->id + TallGrass::TALL_GRASS * 256);
|
||||
level->setTile(xx, yy, zz, 0);
|
||||
ate = true;
|
||||
} else */if (level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) {
|
||||
level->levelEvent(NULL, LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy - 1, zz, ((Tile*)Tile::grass)->id);
|
||||
level->setTile(xx, yy - 1, zz, Tile::dirt->id);
|
||||
ate = true;
|
||||
}
|
||||
if (ate) {
|
||||
setSheared(false);
|
||||
if (isBaby()) {
|
||||
// remove a minute from aging
|
||||
int age = getAge() + SharedConstants::TicksPerSecond * 60;
|
||||
if (age > 0) {
|
||||
age = 0;
|
||||
}
|
||||
setAge(age);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Sheep::shouldHoldGround()
|
||||
{
|
||||
return eatAnimationTick > 0;
|
||||
}
|
||||
|
||||
const char* Sheep::getAmbientSound()
|
||||
{
|
||||
return "mob.sheep";
|
||||
}
|
||||
|
||||
std::string Sheep::getHurtSound()
|
||||
{
|
||||
return "mob.sheep";
|
||||
}
|
||||
|
||||
std::string Sheep::getDeathSound()
|
||||
{
|
||||
return "mob.sheep";
|
||||
}
|
||||
91
src/world/entity/animal/Sheep.h
Executable file
91
src/world/entity/animal/Sheep.h
Executable file
@@ -0,0 +1,91 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Sheep_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Sheep_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "Animal.h"
|
||||
|
||||
#include "../EntityEvent.h"
|
||||
#include "../item/ItemEntity.h"
|
||||
#include "../player/Player.h"
|
||||
#include "../../item/ItemInstance.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../SharedConstants.h"
|
||||
#include "../../../util/Mth.h"
|
||||
|
||||
#include "../../item/Item.h"
|
||||
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
class Sheep: public Animal
|
||||
{
|
||||
typedef Animal super;
|
||||
|
||||
static const int EAT_ANIMATION_TICKS = SharedConstants::TicksPerSecond * 2;
|
||||
static const int DATA_WOOL_ID = 16;
|
||||
|
||||
public:
|
||||
static const float COLOR[][3];
|
||||
static const int NumColors;
|
||||
|
||||
Sheep(Level* level);
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
/*@Override*/
|
||||
void aiStep();
|
||||
|
||||
//*@Override*/
|
||||
void handleEntityEvent(char id);
|
||||
|
||||
float getHeadEatPositionScale(float a);
|
||||
float getHeadEatAngleScale(float a);
|
||||
|
||||
/*@Override*/
|
||||
bool interact(Player* player);
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
int getColor() const;
|
||||
void setColor(int color);
|
||||
|
||||
static int getSheepColor(Random* random);
|
||||
|
||||
bool isSheared() const;
|
||||
void setSheared(bool value);
|
||||
|
||||
int getEntityTypeId() const;
|
||||
protected:
|
||||
/*@Override*/
|
||||
void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/);
|
||||
/*@Override*/
|
||||
int getDeathLoot();
|
||||
|
||||
/*@Override*/
|
||||
void jumpFromGround();
|
||||
|
||||
/*@Override*/
|
||||
void updateAi();
|
||||
|
||||
/*@Override*/
|
||||
bool shouldHoldGround();
|
||||
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
// /*@Override*/
|
||||
// Animal getBreedOffspring(Animal target) {
|
||||
// Sheep otherSheep = (Sheep) target;
|
||||
// Sheep sheep = /*new*/ Sheep(level);
|
||||
// if (random.nextBoolean()) sheep.setColor(getColor());
|
||||
// else sheep.setColor(otherSheep.getColor());
|
||||
// return sheep;
|
||||
// }
|
||||
private:
|
||||
int eatAnimationTick;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__Sheep_H__*/
|
||||
48
src/world/entity/animal/WaterAnimal.cpp
Executable file
48
src/world/entity/animal/WaterAnimal.cpp
Executable file
@@ -0,0 +1,48 @@
|
||||
#include "WaterAnimal.h"
|
||||
#include "../../level/Level.h"
|
||||
|
||||
|
||||
WaterAnimal::WaterAnimal( Level* level )
|
||||
: super(level)
|
||||
{
|
||||
}
|
||||
|
||||
bool WaterAnimal::isWaterMob()
|
||||
{
|
||||
// prevent drowning
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaterAnimal::addAdditonalSaveData( CompoundTag* entityTag )
|
||||
{
|
||||
super::addAdditonalSaveData(entityTag);
|
||||
}
|
||||
|
||||
void WaterAnimal::readAdditionalSaveData( CompoundTag* tag )
|
||||
{
|
||||
super::readAdditionalSaveData(tag);
|
||||
}
|
||||
|
||||
bool WaterAnimal::canSpawn()
|
||||
{
|
||||
return level->isUnobstructed(bb);
|
||||
}
|
||||
|
||||
int WaterAnimal::getAmbientSoundInterval()
|
||||
{
|
||||
return SharedConstants::TicksPerSecond * 6;
|
||||
}
|
||||
|
||||
bool WaterAnimal::removeWhenFarAway()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int WaterAnimal::getExperienceReward( Player* killedBy )
|
||||
{
|
||||
return 1 + level->random.nextInt(3);
|
||||
}
|
||||
|
||||
int WaterAnimal::getCreatureBaseType() const {
|
||||
return MobTypes::BaseWaterCreature;
|
||||
}
|
||||
46
src/world/entity/animal/WaterAnimal.h
Executable file
46
src/world/entity/animal/WaterAnimal.h
Executable file
@@ -0,0 +1,46 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ANIMAL__WaterAnimal_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ANIMAL__WaterAnimal_H__
|
||||
|
||||
//package net.minecraft.world.entity.animal;
|
||||
|
||||
#include "../PathfinderMob.h"
|
||||
#include "../Creature.h"
|
||||
|
||||
class Level;
|
||||
class Player;
|
||||
class CompoundTag;
|
||||
|
||||
/**
|
||||
* The purpose of this class is to offer a new base class for MobCategory.
|
||||
* {@link MobCategory}
|
||||
*
|
||||
* Note: Can't extend Animal because then water animals would prevent normal
|
||||
* animals to spawn, due to MobCategory.getMaxInstancesPerChunk(). This class is
|
||||
* otherwise similar to Animal
|
||||
*
|
||||
*/
|
||||
class WaterAnimal: public PathfinderMob, public Creature
|
||||
{
|
||||
typedef PathfinderMob super;
|
||||
public:
|
||||
WaterAnimal(Level* level);
|
||||
|
||||
/*@Override*/
|
||||
bool isWaterMob();
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
bool canSpawn();
|
||||
|
||||
int getAmbientSoundInterval();
|
||||
int getCreatureBaseType() const;
|
||||
|
||||
protected:
|
||||
bool removeWhenFarAway();
|
||||
|
||||
/*@Override*/
|
||||
int getExperienceReward(Player* killedBy);
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ANIMAL__WaterAnimal_H__*/
|
||||
117
src/world/entity/item/FallingTile.cpp
Executable file
117
src/world/entity/item/FallingTile.cpp
Executable file
@@ -0,0 +1,117 @@
|
||||
#include "FallingTile.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../util/Random.h"
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
|
||||
FallingTile::FallingTile( Level* level )
|
||||
: Entity(level),
|
||||
tile(0),
|
||||
data(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
FallingTile::FallingTile( Level* level, float x, float y, float z, int tile, int data)
|
||||
: Entity(level),
|
||||
tile(tile),
|
||||
data(data)
|
||||
{
|
||||
init();
|
||||
|
||||
setPos(x, y, z);
|
||||
xo = xOld = x;
|
||||
yo = yOld = y;
|
||||
zo = zOld = z;
|
||||
}
|
||||
|
||||
void FallingTile::init() {
|
||||
entityRendererId = ER_FALLINGTILE_RENDERER;
|
||||
|
||||
time = 0;
|
||||
blocksBuilding = true;
|
||||
setSize(0.98f, 0.98f);
|
||||
heightOffset = bbHeight / 2.0f;
|
||||
|
||||
makeStepSound = false;
|
||||
|
||||
xd = 0;
|
||||
yd = 0;
|
||||
zd = 0;
|
||||
}
|
||||
|
||||
bool FallingTile::isPickable() {
|
||||
return !removed;
|
||||
}
|
||||
|
||||
void FallingTile::tick() {
|
||||
if (tile == 0) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
time++;
|
||||
|
||||
yd -= 0.04f;
|
||||
move(xd, yd, zd);
|
||||
xd *= 0.98f;
|
||||
yd *= 0.98f;
|
||||
zd *= 0.98f;
|
||||
|
||||
if (!level->isClientSide) {
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(y);
|
||||
int zt = Mth::floor(z);
|
||||
|
||||
if (time == 1) {
|
||||
if (level->getTile(xt, yt, zt) == tile) {
|
||||
level->setTile(xt, yt, zt, 0);
|
||||
} else {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (onGround) {
|
||||
xd *= 0.7f;
|
||||
zd *= 0.7f;
|
||||
yd *= -0.5f;
|
||||
|
||||
remove();
|
||||
if (level->mayPlace(tile, xt, yt, zt, true, 1) && level->setTileAndData(xt, yt, zt, tile, data)) {
|
||||
} else if (!level->isClientSide) {
|
||||
//spawnAtLocation(tile, 1);
|
||||
}
|
||||
} else if (time > SharedConstants::TicksPerSecond * 5 && !level->isClientSide) {
|
||||
//spawnAtLocation(tile, 1);
|
||||
remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float FallingTile::getShadowHeightOffs() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Level* FallingTile::getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
void FallingTile::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
tag->putByte("Tile", (char) tile);
|
||||
tag->putByte("Data", (char) data);
|
||||
tag->putByte("Time", (char) time);
|
||||
}
|
||||
|
||||
void FallingTile::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
tile = tag->getByte("Tile");
|
||||
data = tag->getByte("Data");
|
||||
time = tag->getByte("Time");
|
||||
}
|
||||
|
||||
int FallingTile::getEntityTypeId() const {
|
||||
return EntityTypes::IdFallingTile;
|
||||
}
|
||||
40
src/world/entity/item/FallingTile.h
Executable file
40
src/world/entity/item/FallingTile.h
Executable file
@@ -0,0 +1,40 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ITEM__FallingTile_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ITEM__FallingTile_H__
|
||||
|
||||
//package net.minecraft.world.entity.item;
|
||||
|
||||
#include "../Entity.h"
|
||||
|
||||
class Level;
|
||||
class CompoundTag;
|
||||
|
||||
class FallingTile: public Entity
|
||||
{
|
||||
public:
|
||||
FallingTile(Level* level);
|
||||
FallingTile(Level* level, float x, float y, float z, int tile, int data = 0);
|
||||
|
||||
void init();
|
||||
|
||||
bool isPickable();
|
||||
|
||||
void tick();
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
float getShadowHeightOffs();
|
||||
|
||||
Level* getLevel();
|
||||
|
||||
protected:
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
public:
|
||||
int tile;
|
||||
int data;
|
||||
|
||||
int time;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ITEM__FallingTile_H__*/
|
||||
211
src/world/entity/item/ItemEntity.cpp
Executable file
211
src/world/entity/item/ItemEntity.cpp
Executable file
@@ -0,0 +1,211 @@
|
||||
#include "ItemEntity.h"
|
||||
#include "../../entity/player/Player.h"
|
||||
#include "../../item/ItemInstance.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../level/material/Material.h"
|
||||
#include "../../level/tile/Tile.h"
|
||||
#include "../../../util/Mth.h"
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
const int ItemEntity::LIFETIME = 5 * 60 * SharedConstants::TicksPerSecond; // Five minutes, changed in 0.3.3!
|
||||
|
||||
ItemEntity::ItemEntity( Level* level, float x, float y, float z, const ItemInstance& item )
|
||||
: super(level),
|
||||
item(item),
|
||||
health(5),
|
||||
age(0),
|
||||
tickCount(0),
|
||||
throwTime(0),
|
||||
lifeTime(LIFETIME),
|
||||
bobOffs((float) (Mth::random() * Mth::PI * 2))
|
||||
{
|
||||
entityRendererId = ER_ITEM_RENDERER;
|
||||
|
||||
setSize(0.25f, 0.25f);
|
||||
heightOffset = bbHeight / 2.0f;
|
||||
setPos(x, y, z);
|
||||
|
||||
yRot = (float) (Mth::random() * 360);
|
||||
|
||||
xd = (float) (Mth::random() * 0.2f - 0.1f);
|
||||
yd = +0.2f;
|
||||
zd = (float) (Mth::random() * 0.2f - 0.1f);
|
||||
makeStepSound = false;
|
||||
}
|
||||
|
||||
ItemEntity::ItemEntity( Level* level )
|
||||
: super(level),
|
||||
health(5),
|
||||
age(0),
|
||||
tickCount(0),
|
||||
throwTime(0),
|
||||
lifeTime(LIFETIME),
|
||||
bobOffs((float) (Mth::random() * Mth::PI * 2))
|
||||
{
|
||||
entityRendererId = ER_ITEM_RENDERER;
|
||||
|
||||
setSize(0.25f, 0.25f);
|
||||
heightOffset = bbHeight / 2.0f;
|
||||
}
|
||||
|
||||
ItemEntity::~ItemEntity()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void ItemEntity::tick()
|
||||
{
|
||||
super::tick();
|
||||
if (throwTime > 0) throwTime--;
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
|
||||
yd -= 0.04f;
|
||||
if (level->getMaterial(Mth::floor(x), Mth::floor(y), Mth::floor(z)) == Material::lava) {
|
||||
yd = 0.2f;
|
||||
xd = (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.2f;
|
||||
zd = (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.2f;
|
||||
level->playSound(this, "random.fizz", 0.4f, 2.0f + sharedRandom.nextFloat() * 0.4f);
|
||||
}
|
||||
checkInTile(x, y, z);
|
||||
move(xd, yd, zd);
|
||||
|
||||
float friction = 0.98f;
|
||||
if (onGround) {
|
||||
friction = 0.6f * 0.98f;
|
||||
int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0) - 1, Mth::floor(z));
|
||||
if (t > 0) {
|
||||
friction = Tile::tiles[t]->friction * 0.98f;
|
||||
}
|
||||
}
|
||||
|
||||
xd *= friction;
|
||||
yd *= 0.98f;
|
||||
zd *= friction;
|
||||
|
||||
if (onGround) {
|
||||
yd *= -0.5f;
|
||||
}
|
||||
|
||||
tickCount++;
|
||||
age++;
|
||||
if (age >= lifeTime) {
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemEntity::isInWater()
|
||||
{
|
||||
return level->checkAndHandleWater(bb, Material::water, this);
|
||||
}
|
||||
|
||||
bool ItemEntity::hurt( Entity* source, int damage )
|
||||
{
|
||||
markHurt();
|
||||
health -= damage;
|
||||
if (health <= 0) {
|
||||
remove();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ItemEntity::playerTouch( Player* player )
|
||||
{
|
||||
if (level->isClientSide) return;
|
||||
|
||||
int orgCount = item.count;
|
||||
if (throwTime == 0 && player->isAlive() && player->inventory->add(&item)) {
|
||||
level->playSound(this, "random.pop", 0.3f, ((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f + 1.0f) * 2.f);
|
||||
player->take(this, orgCount);
|
||||
//if (item.count <= 0) remove(); //@todo
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
void ItemEntity::burn( int dmg )
|
||||
{
|
||||
hurt(NULL, dmg);
|
||||
}
|
||||
|
||||
bool ItemEntity::checkInTile( float x, float y, float z )
|
||||
{
|
||||
int xTile = Mth::floor(x);
|
||||
int yTile = Mth::floor(y);
|
||||
int zTile = Mth::floor(z);
|
||||
|
||||
float xd = x - xTile;
|
||||
float yd = y - yTile;
|
||||
float zd = z - zTile;
|
||||
|
||||
if (Tile::solid[level->getTile(xTile, yTile, zTile)]) {
|
||||
bool west = !Tile::solid[level->getTile(xTile - 1, yTile, zTile)];
|
||||
bool east = !Tile::solid[level->getTile(xTile + 1, yTile, zTile)];
|
||||
bool up = !Tile::solid[level->getTile(xTile, yTile - 1, zTile)];
|
||||
bool down = !Tile::solid[level->getTile(xTile, yTile + 1, zTile)];
|
||||
bool north = !Tile::solid[level->getTile(xTile, yTile, zTile - 1)];
|
||||
bool south = !Tile::solid[level->getTile(xTile, yTile, zTile + 1)];
|
||||
|
||||
int dir = -1;
|
||||
float closest = 9999;
|
||||
if (west && xd < closest) {
|
||||
closest = xd;
|
||||
dir = 0;
|
||||
}
|
||||
if (east && 1 - xd < closest) {
|
||||
closest = 1 - xd;
|
||||
dir = 1;
|
||||
}
|
||||
if (up && yd < closest) {
|
||||
closest = yd;
|
||||
dir = 2;
|
||||
}
|
||||
if (down && 1 - yd < closest) {
|
||||
closest = 1 - yd;
|
||||
dir = 3;
|
||||
}
|
||||
if (north && zd < closest) {
|
||||
closest = zd;
|
||||
dir = 4;
|
||||
}
|
||||
if (south && 1 - zd < closest) {
|
||||
// closest = 1 - zd; //@note: not read
|
||||
dir = 5;
|
||||
}
|
||||
|
||||
float speed = sharedRandom.nextFloat() * 0.2f + 0.1f;
|
||||
if (dir == 0) this->xd = -speed;
|
||||
if (dir == 1) this->xd = +speed;
|
||||
if (dir == 2) this->yd = -speed;
|
||||
if (dir == 3) this->yd = +speed;
|
||||
if (dir == 4) this->zd = -speed;
|
||||
if (dir == 5) this->zd = +speed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ItemEntity::addAdditonalSaveData(CompoundTag* entityTag) {
|
||||
entityTag->putShort("Health", (char) health);
|
||||
entityTag->putShort("Age", (short) age);
|
||||
entityTag->putCompound("Item", item.save(new CompoundTag()));
|
||||
}
|
||||
|
||||
void ItemEntity::readAdditionalSaveData(CompoundTag* tag) {
|
||||
health = tag->getShort("Health") & 0xff;
|
||||
age = tag->getShort("Age");
|
||||
CompoundTag* itemTag = tag->getCompound("Item");
|
||||
item.load(itemTag);
|
||||
}
|
||||
|
||||
bool ItemEntity::isItemEntity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int ItemEntity::getEntityTypeId() const {
|
||||
return EntityTypes::IdItemEntity;
|
||||
}
|
||||
|
||||
int ItemEntity::getLifeTime() const {
|
||||
return lifeTime;
|
||||
}
|
||||
49
src/world/entity/item/ItemEntity.h
Executable file
49
src/world/entity/item/ItemEntity.h
Executable file
@@ -0,0 +1,49 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ITEM__ItemEntity_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ITEM__ItemEntity_H__
|
||||
|
||||
//package net.minecraft.world.entity.item;
|
||||
|
||||
#include "../../item/ItemInstance.h"
|
||||
#include "../../entity/Entity.h"
|
||||
#include "../../../SharedConstants.h"
|
||||
|
||||
class Level;
|
||||
class ItemInstance;
|
||||
|
||||
class ItemEntity: public Entity
|
||||
{
|
||||
typedef Entity super;
|
||||
|
||||
static const int LIFETIME;
|
||||
public:
|
||||
ItemEntity(Level* level);
|
||||
ItemEntity(Level* level, float x, float y, float z, const ItemInstance& item);
|
||||
~ItemEntity();
|
||||
|
||||
void tick();
|
||||
bool isInWater();
|
||||
bool hurt(Entity* source, int damage);
|
||||
void playerTouch(Player* player);
|
||||
bool isItemEntity();
|
||||
int getEntityTypeId() const;
|
||||
int getLifeTime() const;
|
||||
protected:
|
||||
void burn(int dmg);
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
private:
|
||||
bool checkInTile(float x, float y, float z);
|
||||
|
||||
public:
|
||||
ItemInstance item;
|
||||
int age;
|
||||
int throwTime;
|
||||
float bobOffs;
|
||||
private:
|
||||
int tickCount;
|
||||
int health;
|
||||
int lifeTime;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ITEM__ItemEntity_H__*/
|
||||
91
src/world/entity/item/PrimedTnt.cpp
Executable file
91
src/world/entity/item/PrimedTnt.cpp
Executable file
@@ -0,0 +1,91 @@
|
||||
#include "PrimedTnt.h"
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
PrimedTnt::PrimedTnt( Level* level )
|
||||
: super(level),
|
||||
life(80)
|
||||
{
|
||||
entityRendererId = ER_TNT_RENDERER ;
|
||||
|
||||
blocksBuilding = true;
|
||||
setSize(0.98f, 0.98f);
|
||||
heightOffset = bbHeight / 2.0f;
|
||||
}
|
||||
|
||||
PrimedTnt::PrimedTnt( Level* level, float x, float y, float z )
|
||||
: super(level),
|
||||
life(80)
|
||||
{
|
||||
entityRendererId = ER_TNT_RENDERER ;
|
||||
|
||||
blocksBuilding = true;
|
||||
setSize(0.98f, 0.98f);
|
||||
heightOffset = bbHeight / 2.0f;
|
||||
|
||||
setPos(x, y, z);
|
||||
|
||||
float rot = Mth::random() * Mth::PI * 2.0f;
|
||||
xd = Mth::sin(rot * Mth::DEGRAD) * -0.02f;
|
||||
yd = +0.2f;
|
||||
zd = Mth::cos(rot * Mth::DEGRAD) * -0.02f;
|
||||
|
||||
makeStepSound = false;
|
||||
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
}
|
||||
|
||||
bool PrimedTnt::isPickable()
|
||||
{
|
||||
return !removed;
|
||||
}
|
||||
|
||||
void PrimedTnt::tick()
|
||||
{
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
|
||||
yd -= 0.04f;
|
||||
move(xd, yd, zd);
|
||||
xd *= 0.98f;
|
||||
yd *= 0.98f;
|
||||
zd *= 0.98f;
|
||||
|
||||
if (onGround) {
|
||||
xd *= 0.7f;
|
||||
zd *= 0.7f;
|
||||
yd *= -0.5f;
|
||||
}
|
||||
life--;
|
||||
if (!level->isClientSide && life <= 0) {
|
||||
remove();
|
||||
explode();
|
||||
} else {
|
||||
level->addParticle(PARTICLETYPE(smoke), x, y + 0.5f, z, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
float PrimedTnt::getShadowHeightOffs()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PrimedTnt::explode()
|
||||
{
|
||||
float r = 3.1f;
|
||||
level->explode(NULL, x, y, z, r);
|
||||
}
|
||||
|
||||
void PrimedTnt::addAdditonalSaveData(CompoundTag* entityTag) {
|
||||
entityTag->putByte("Fuse", life);
|
||||
}
|
||||
|
||||
void PrimedTnt::readAdditionalSaveData(CompoundTag* tag) {
|
||||
life = tag->getByte("Fuse");
|
||||
}
|
||||
|
||||
int PrimedTnt::getEntityTypeId() const {
|
||||
return EntityTypes::IdPrimedTnt;
|
||||
}
|
||||
36
src/world/entity/item/PrimedTnt.h
Executable file
36
src/world/entity/item/PrimedTnt.h
Executable file
@@ -0,0 +1,36 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ITEM__PrimedTnt_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ITEM__PrimedTnt_H__
|
||||
|
||||
//package net.minecraft.world.entity.item;
|
||||
|
||||
#include "../Entity.h"
|
||||
#include "../../level/Level.h"
|
||||
|
||||
class CompoundTag;
|
||||
|
||||
|
||||
class PrimedTnt: public Entity
|
||||
{
|
||||
typedef Entity super;
|
||||
public:
|
||||
PrimedTnt(Level* level);
|
||||
PrimedTnt(Level* level, float x, float y, float z);
|
||||
|
||||
void tick();
|
||||
|
||||
bool isPickable();
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
float getShadowHeightOffs();
|
||||
protected:
|
||||
void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
private:
|
||||
void explode();
|
||||
|
||||
public:
|
||||
int life;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ITEM__PrimedTnt_H__*/
|
||||
88
src/world/entity/item/TripodCamera.cpp
Executable file
88
src/world/entity/item/TripodCamera.cpp
Executable file
@@ -0,0 +1,88 @@
|
||||
#include "TripodCamera.h"
|
||||
#include "../player/Player.h"
|
||||
#include "../../level/Level.h"
|
||||
|
||||
|
||||
TripodCamera::TripodCamera( Level* level, Player* owner, float x, float y, float z )
|
||||
: super(level),
|
||||
owner(owner),
|
||||
life(80),
|
||||
activated(false)
|
||||
{
|
||||
entityRendererId = ER_TRIPODCAMERA_RENDERER;
|
||||
|
||||
// Copy rotation from the entity placing the camera
|
||||
xRot = xRotO = owner->xRot;
|
||||
yRot = yRotO = owner->yRot;
|
||||
|
||||
blocksBuilding = true;
|
||||
setSize(1.0f, 1.5f);
|
||||
heightOffset = bbHeight / 2.0f - 0.25f;
|
||||
|
||||
setPos(x, y, z);
|
||||
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
}
|
||||
|
||||
bool TripodCamera::isPickable()
|
||||
{
|
||||
return !removed;
|
||||
}
|
||||
|
||||
bool TripodCamera::interactPreventDefault()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TripodCamera::interact( Player* player )
|
||||
{
|
||||
activated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TripodCamera::tick()
|
||||
{
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
|
||||
yd -= 0.04f;
|
||||
move(xd, yd, zd);
|
||||
xd *= 0.98f;
|
||||
yd *= 0.98f;
|
||||
zd *= 0.98f;
|
||||
|
||||
if (onGround) {
|
||||
xd *= 0.7f;
|
||||
zd *= 0.7f;
|
||||
yd *= -0.5f;
|
||||
}
|
||||
|
||||
if (activated) {
|
||||
--life;
|
||||
|
||||
if (life == 0) {
|
||||
remove();
|
||||
} else if (life == 8) {
|
||||
level->takePicture(this, owner);
|
||||
level->addParticle(PARTICLETYPE(explode), x, y + 0.6f, z, 0, 0, 0);
|
||||
level->addParticle(PARTICLETYPE(explode), x, y + 0.8f, z, 0, 0, 0);
|
||||
level->addParticle(PARTICLETYPE(explode), x, y + 1.0f, z, 0, 0, 0);
|
||||
} else if (life > 8) {
|
||||
level->addParticle(PARTICLETYPE(smoke), x, y + 1.0f, z, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float TripodCamera::getShadowHeightOffs()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TripodCamera::isPushable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
32
src/world/entity/item/TripodCamera.h
Executable file
32
src/world/entity/item/TripodCamera.h
Executable file
@@ -0,0 +1,32 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_ITEM__TripodCamera_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_ITEM__TripodCamera_H__
|
||||
|
||||
#include "../Mob.h"
|
||||
|
||||
class TripodCamera: public Mob
|
||||
{
|
||||
typedef Mob super;
|
||||
public:
|
||||
TripodCamera(Level* level, Player* owner_, float x, float y, float z);
|
||||
|
||||
void tick();
|
||||
|
||||
bool isPickable();
|
||||
bool isPushable();
|
||||
|
||||
// id == 0 -> not possible to create via serialization (yet)
|
||||
int getEntityTypeId() const { return 0; }
|
||||
|
||||
bool interact(Player* player);
|
||||
bool interactPreventDefault();
|
||||
|
||||
float getShadowHeightOffs();
|
||||
public:
|
||||
int life;
|
||||
protected:
|
||||
Player* owner;
|
||||
bool activated;
|
||||
};
|
||||
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_ITEM__TripodCamera_H__*/
|
||||
114
src/world/entity/monster/Creeper.cpp
Executable file
114
src/world/entity/monster/Creeper.cpp
Executable file
@@ -0,0 +1,114 @@
|
||||
#include "Creeper.h"
|
||||
#include "../Entity.h"
|
||||
#include "../../item/Item.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
Creeper::Creeper( Level* level )
|
||||
: super(level),
|
||||
swell(0),
|
||||
oldSwell(0),
|
||||
swellDir(-1)
|
||||
{
|
||||
entityRendererId = ER_CREEPER_RENDERER;
|
||||
this->textureName = "mob/creeper.png";
|
||||
|
||||
entityData.define(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) -1);
|
||||
}
|
||||
|
||||
int Creeper::getMaxHealth() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void Creeper::tick() {
|
||||
oldSwell = swell;
|
||||
if (level->isClientSide) {
|
||||
int swellDir = getSwellDir();
|
||||
if (swellDir > 0 && swell == 0) {
|
||||
level->playSound(this, "random.fuse", 1, 0.5f);
|
||||
}
|
||||
swell += swellDir;
|
||||
if (swell < 0) swell = 0;
|
||||
if (swell >= MAX_SWELL) swell = MAX_SWELL;
|
||||
}
|
||||
super::tick();
|
||||
|
||||
if (!level->isClientSide && attackTargetId == 0) {
|
||||
if (swell > 0) {
|
||||
setSwellDir(-1);
|
||||
swell--;
|
||||
if (swell < 0) {
|
||||
swell = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Creeper::getSwelling( float a ) {
|
||||
return (oldSwell + (swell - oldSwell) * a) / (MAX_SWELL - 2);
|
||||
}
|
||||
|
||||
int Creeper::getEntityTypeId() const {
|
||||
return MobTypes::Creeper;
|
||||
}
|
||||
|
||||
int Creeper::getDeathLoot() {
|
||||
return Item::sulphur->id;
|
||||
}
|
||||
|
||||
void Creeper::checkCantSeeTarget( Entity* target, float d ) {
|
||||
if (level->isClientSide) return;
|
||||
if (swell > 0) {
|
||||
setSwellDir(-1);
|
||||
swell--;
|
||||
if (swell < 0) {
|
||||
swell = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Creeper::getHurtSound() {
|
||||
return "mob.creeper";
|
||||
}
|
||||
|
||||
std::string Creeper::getDeathSound() {
|
||||
return "mob.creeperdeath";
|
||||
}
|
||||
|
||||
void Creeper::checkHurtTarget( Entity* target, float d ) {
|
||||
if (level->isClientSide) return;
|
||||
const int swellDir = getSwellDir();
|
||||
if ((swellDir <= 0 && d < 3) || (swellDir > 0 && d < 7)) {
|
||||
if (swell == 0) {
|
||||
level->playSound(this, "random.fuse", 1, 0.5f);
|
||||
}
|
||||
setSwellDir(1);
|
||||
|
||||
if (++swell >= MAX_SWELL) {
|
||||
level->explode(this, x, y, z, 2.4f);
|
||||
remove();
|
||||
}
|
||||
holdGround = true;
|
||||
} else {
|
||||
setSwellDir(-1);
|
||||
if (--swell < 0)
|
||||
swell = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Creeper::getSwellDir() {
|
||||
return (int) entityData.getByte(DATA_SWELL_DIR);
|
||||
}
|
||||
|
||||
void Creeper::setSwellDir( int dir ) {
|
||||
entityData.set(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) dir);
|
||||
}
|
||||
|
||||
//@todo
|
||||
//void die(DamageSource* source) {
|
||||
// super::die(source);
|
||||
|
||||
// if (source.getEntity() instanceof Skeleton) {
|
||||
// spawnAtLocation(Item::record_01->id + random.nextInt(2), 1);
|
||||
// }
|
||||
//}
|
||||
46
src/world/entity/monster/Creeper.h
Executable file
46
src/world/entity/monster/Creeper.h
Executable file
@@ -0,0 +1,46 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Creeper_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Creeper_H__
|
||||
|
||||
//package net.minecraft.world.entity.monster;
|
||||
|
||||
#include "Monster.h"
|
||||
#include <string>
|
||||
|
||||
class Entity;
|
||||
|
||||
class Creeper: public Monster
|
||||
{
|
||||
typedef Monster super;
|
||||
public:
|
||||
Creeper(Level* level);
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
void tick();
|
||||
|
||||
float getSwelling(float a);
|
||||
|
||||
virtual int getEntityTypeId() const;
|
||||
protected:
|
||||
int getDeathLoot();
|
||||
|
||||
void checkCantSeeTarget(Entity* target, float d);
|
||||
void checkHurtTarget(Entity* target, float d);
|
||||
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
private:
|
||||
int getSwellDir();
|
||||
void setSwellDir(int dir);
|
||||
|
||||
int swell;
|
||||
int oldSwell;
|
||||
|
||||
int swellDir;
|
||||
|
||||
static const int DATA_SWELL_DIR = 16;
|
||||
static const int MAX_SWELL = 30;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Creeper_H__*/
|
||||
144
src/world/entity/monster/Monster.cpp
Executable file
144
src/world/entity/monster/Monster.cpp
Executable file
@@ -0,0 +1,144 @@
|
||||
#include "Monster.h"
|
||||
|
||||
#include "../player/Player.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../Difficulty.h"
|
||||
#include "../../../util/Mth.h"
|
||||
//#include "../../effect/MobEffect.h"
|
||||
|
||||
Monster::Monster(Level* level)
|
||||
: super(level),
|
||||
attackDamage(2),
|
||||
targetId(0),
|
||||
lastHurtByMobId(0)
|
||||
{
|
||||
entityRendererId = ER_HUMANOID_RENDERER;
|
||||
//xpReward = Enemy.XP_REWARD_MEDIUM;
|
||||
}
|
||||
|
||||
void Monster::aiStep()
|
||||
{
|
||||
updateAttackAnim();
|
||||
|
||||
float br = getBrightness(1);
|
||||
if (br > 0.5f) {
|
||||
noActionTime += 2;
|
||||
}
|
||||
super::aiStep();
|
||||
}
|
||||
|
||||
void Monster::tick()
|
||||
{
|
||||
super::tick();
|
||||
if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove();
|
||||
}
|
||||
|
||||
bool Monster::hurt( Entity* sourceEntity, int dmg )
|
||||
{
|
||||
if (super::hurt(sourceEntity, dmg)) {
|
||||
if (sourceEntity != this) {
|
||||
attackTargetId = 0;
|
||||
if (sourceEntity != NULL) {
|
||||
attackTargetId = sourceEntity->entityId;
|
||||
if (sourceEntity->isMob())
|
||||
lastHurtByMobId = sourceEntity->entityId;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Monster::canSpawn()
|
||||
{
|
||||
return isDarkEnoughToSpawn() && super::canSpawn();
|
||||
}
|
||||
|
||||
Entity* Monster::findAttackTarget()
|
||||
{
|
||||
//Player* player = level->getNearestAttackablePlayer(this, 16);
|
||||
Player* player = level->getNearestPlayer(this, 16);
|
||||
//LOGI("playuer: %p\n", player);
|
||||
if (player != NULL && canSee(player)) return player;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Monster::isDarkEnoughToSpawn()
|
||||
{
|
||||
//static int st = getTimeMs();
|
||||
//return getTimeMs() - st > 10000;
|
||||
|
||||
int xt = Mth::floor(x);
|
||||
int yt = Mth::floor(bb.y0);
|
||||
int zt = Mth::floor(z);
|
||||
if (level->getBrightness(LightLayer::Sky, xt, yt, zt) > random.nextInt(32)) return false;
|
||||
|
||||
int br = level->getRawBrightness(xt, yt, zt);
|
||||
|
||||
//if (level->isThundering()) {
|
||||
// int tmp = level->skyDarken;
|
||||
// level->skyDarken = 10;
|
||||
// br = level->getRawBrightness(xt, yt, zt);
|
||||
// level->skyDarken = tmp;
|
||||
//}
|
||||
//LOGI("br: %d\n", br);
|
||||
return br <= random.nextInt(8); // was 8
|
||||
}
|
||||
|
||||
bool Monster::doHurtTarget( Entity* target )
|
||||
{
|
||||
swing();
|
||||
//if (target->isMob()) setLastHurtMob(target);
|
||||
//@todo
|
||||
int dmg = attackDamage;
|
||||
//if (hasEffect(MobEffect.damageBoost)) {
|
||||
// dmg += (3 << getEffect(MobEffect.damageBoost).getAmplifier());
|
||||
//}
|
||||
//if (hasEffect(MobEffect.weakness)) {
|
||||
// dmg -= (2 << getEffect(MobEffect.weakness).getAmplifier());
|
||||
//}
|
||||
|
||||
return target->hurt(this, dmg);
|
||||
}
|
||||
|
||||
void Monster::checkHurtTarget( Entity* target, float distance ) {
|
||||
if (attackTime <= 0 && distance < 2.0f && target->bb.y1 > bb.y0 && target->bb.y0 < bb.y1) {
|
||||
attackTime = getAttackTime();
|
||||
doHurtTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
float Monster::getWalkTargetValue( int x, int y, int z )
|
||||
{
|
||||
return 0.5f - level->getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
int Monster::getCreatureBaseType() const {
|
||||
return MobTypes::BaseEnemy;
|
||||
}
|
||||
|
||||
Mob* Monster::getTarget() {
|
||||
if (targetId == 0) return NULL;
|
||||
return level->getMob(targetId);
|
||||
}
|
||||
|
||||
void Monster::setTarget(Mob* mob) {
|
||||
targetId = mob? mob->entityId : 0;
|
||||
}
|
||||
|
||||
Mob* Monster::getLastHurtByMob() {
|
||||
if (targetId == 0) return NULL;
|
||||
return level->getMob(lastHurtByMobId);
|
||||
}
|
||||
|
||||
void Monster::setLastHurtByMob(Mob* mob) {
|
||||
lastHurtByMobId = mob? mob->entityId : 0;
|
||||
}
|
||||
|
||||
int Monster::getAttackDamage( Entity* target ) {
|
||||
return attackDamage;
|
||||
}
|
||||
|
||||
int Monster::getAttackTime() {
|
||||
return 20;
|
||||
}
|
||||
57
src/world/entity/monster/Monster.h
Executable file
57
src/world/entity/monster/Monster.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Monster_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Monster_H__
|
||||
|
||||
//package net.minecraft.world.entity->monster;
|
||||
|
||||
#include "../PathfinderMob.h"
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
//class DamageSource;
|
||||
class CompoundTag;
|
||||
|
||||
class Monster: public PathfinderMob//implements Enemy
|
||||
{
|
||||
typedef PathfinderMob super;
|
||||
public:
|
||||
Monster(Level* level);
|
||||
|
||||
void aiStep();
|
||||
void tick();
|
||||
|
||||
//bool hurt(DamageSource* source, int dmg) {
|
||||
bool hurt(Entity* sourceEntity, int dmg);
|
||||
|
||||
/*@Override*/
|
||||
bool canSpawn();
|
||||
|
||||
int getCreatureBaseType() const;
|
||||
|
||||
bool doHurtTarget(Entity* target);
|
||||
void setTarget(Mob* mob);
|
||||
Mob* getTarget();
|
||||
|
||||
Mob* getLastHurtByMob();
|
||||
void setLastHurtByMob(Mob* mob);
|
||||
virtual int getAttackDamage(Entity* target);
|
||||
protected:
|
||||
Entity* findAttackTarget();
|
||||
|
||||
bool isDarkEnoughToSpawn();
|
||||
/**
|
||||
* Performs hurt action, returns if successful
|
||||
*
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
void checkHurtTarget(Entity* target, float distance);
|
||||
|
||||
float getWalkTargetValue(int x, int y, int z);
|
||||
virtual int getAttackTime();
|
||||
int attackDamage;
|
||||
int targetId;
|
||||
|
||||
int lastHurtByMobId;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Monster_H__*/
|
||||
10
src/world/entity/monster/MonsterInclude.h
Executable file
10
src/world/entity/monster/MonsterInclude.h
Executable file
@@ -0,0 +1,10 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__MonsterInclude_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__MonsterInclude_H__
|
||||
|
||||
#include "Creeper.h"
|
||||
#include "Monster.h"
|
||||
#include "Skeleton.h"
|
||||
#include "Spider.h"
|
||||
#include "Zombie.h"
|
||||
#include "PigZombie.h"
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__MonsterInclude_H__*/
|
||||
138
src/world/entity/monster/PigZombie.cpp
Executable file
138
src/world/entity/monster/PigZombie.cpp
Executable file
@@ -0,0 +1,138 @@
|
||||
#include "PigZombie.h"
|
||||
#include "../../item/Item.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../Difficulty.h"
|
||||
#include "../Entity.h"
|
||||
#include "../projectile/Arrow.h"
|
||||
PigZombie::PigZombie( Level* level )
|
||||
: super(level)
|
||||
, angerTime(0)
|
||||
, playAngrySoundIn(0)
|
||||
, weapon(Item::sword_gold)
|
||||
, stunedTime(SharedConstants::TicksPerSecond * 3){
|
||||
textureName = "mob/pigzombie.png";
|
||||
runSpeed = 0.7f;
|
||||
fireImmune = true;
|
||||
attackDamage = 5;
|
||||
}
|
||||
|
||||
bool PigZombie::useNewAi() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PigZombie::tick() {
|
||||
//runSpeed = attackTargetId != 0 ? 0.95f : 0.5f;
|
||||
if(stunedTime > 0)
|
||||
stunedTime--;
|
||||
if(playAngrySoundIn > 0) {
|
||||
if(--playAngrySoundIn == 0) {
|
||||
level->playSound(x, y, z, "mob.zombiepig.zpigangry", getSoundVolume() * 2, ((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f) * 1.8f);
|
||||
}
|
||||
}
|
||||
super::tick();
|
||||
}
|
||||
|
||||
std::string PigZombie::getTexture() {
|
||||
return "mob/pigzombie.png";
|
||||
}
|
||||
|
||||
bool PigZombie::canSpawn() {
|
||||
return level->difficulty > Difficulty::PEACEFUL && level->isUnobstructed(bb) && level->getCubes(this, bb).empty();
|
||||
}
|
||||
|
||||
void PigZombie::addAdditonalSaveData( CompoundTag* entityTag ) {
|
||||
super::addAdditonalSaveData(entityTag);
|
||||
entityTag->putShort("Anger", (short)angerTime);
|
||||
}
|
||||
|
||||
void PigZombie::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
super::readAdditionalSaveData(tag);
|
||||
angerTime = tag->getShort("Anger");
|
||||
}
|
||||
|
||||
Entity* PigZombie::findAttackTarget() {
|
||||
if(stunedTime != 0)
|
||||
return NULL;
|
||||
if(angerTime == 0) {
|
||||
Entity* potentialTarget = super::findAttackTarget();
|
||||
if(potentialTarget != NULL && potentialTarget->distanceTo(x, y, z) < 5) {
|
||||
return potentialTarget;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return super::findAttackTarget();
|
||||
}
|
||||
|
||||
bool PigZombie::hurt( Entity* sourceEntity, int dmg ) {
|
||||
Entity* attacker = NULL;
|
||||
if(sourceEntity != NULL) {
|
||||
if(sourceEntity->isPlayer()) {
|
||||
attacker = sourceEntity;
|
||||
}
|
||||
else if(sourceEntity->isEntityType(EntityTypes::IdArrow)) {
|
||||
Arrow* arrow = (Arrow*)sourceEntity;
|
||||
if(arrow->ownerId != 0) {
|
||||
attacker = level->getEntity(arrow->ownerId);
|
||||
if(!attacker->isPlayer())
|
||||
attacker = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(attacker != NULL) {
|
||||
EntityList nearby = level->getEntities(this, bb.grow(12, 12, 12));
|
||||
for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) {
|
||||
if((*it)->isEntityType(MobTypes::PigZombie)) {
|
||||
PigZombie* pigZombie = (PigZombie*)(*it);
|
||||
pigZombie->alert(sourceEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super::hurt(sourceEntity, dmg);
|
||||
}
|
||||
|
||||
void PigZombie::alert( Entity* target ) {
|
||||
attackTargetId = target->entityId;
|
||||
angerTime = 20 * 20 * random.nextInt(20 * 20);
|
||||
playAngrySoundIn = random.nextInt(20 * 2);
|
||||
}
|
||||
|
||||
const char* PigZombie::getAmbientSound() {
|
||||
return "mob.zombiepig.zpig";
|
||||
}
|
||||
|
||||
std::string PigZombie::getHurtSound() {
|
||||
return "mob.zombiepig.zpighurt";
|
||||
}
|
||||
|
||||
std::string PigZombie::getDeathSound() {
|
||||
return "mob.zombiepig.zpigdeath";
|
||||
}
|
||||
|
||||
void PigZombie::dropDeathLoot() {
|
||||
int count = random.nextInt(2);
|
||||
for(int i = 0; i < count; ++i) {
|
||||
// We really should spawn gold nuggets instead of ingots.
|
||||
spawnAtLocation(Item::goldIngot->id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool PigZombie::interact( Player* player ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int PigZombie::getDeathLoot() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemInstance* PigZombie::getCarriedItem() {
|
||||
return &weapon;
|
||||
}
|
||||
|
||||
int PigZombie::getEntityTypeId() const {
|
||||
return MobTypes::PigZombie;
|
||||
}
|
||||
|
||||
int PigZombie::getAttackTime() {
|
||||
return 40;
|
||||
}
|
||||
38
src/world/entity/monster/PigZombie.h
Executable file
38
src/world/entity/monster/PigZombie.h
Executable file
@@ -0,0 +1,38 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__PigZombie_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__PigZombie_H__
|
||||
|
||||
#include "Zombie.h"
|
||||
class ItemInstance;
|
||||
class PigZombie : public Zombie {
|
||||
typedef Zombie super;
|
||||
public:
|
||||
PigZombie(Level* level);
|
||||
bool useNewAi();
|
||||
void tick();
|
||||
std::string getTexture();
|
||||
bool canSpawn();
|
||||
void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
bool hurt(Entity* sourceEntity, int dmg);
|
||||
bool interact(Player* player);
|
||||
int getEntityTypeId() const;
|
||||
virtual int getAttackTime();
|
||||
ItemInstance* getCarriedItem();
|
||||
protected:
|
||||
Entity* findAttackTarget();
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
void dropDeathLoot();
|
||||
int getDeathLoot();
|
||||
private:
|
||||
void alert(Entity* target);
|
||||
|
||||
private:
|
||||
int angerTime;
|
||||
int playAngrySoundIn;
|
||||
int stunedTime;
|
||||
ItemInstance weapon;
|
||||
};
|
||||
|
||||
#endif /* NET_MINECRAFT_WORLD_ENTITY_MONSTER__PigZombie_H__ */
|
||||
107
src/world/entity/monster/Skeleton.cpp
Executable file
107
src/world/entity/monster/Skeleton.cpp
Executable file
@@ -0,0 +1,107 @@
|
||||
#include "Skeleton.h"
|
||||
#include "../projectile/Arrow.h"
|
||||
|
||||
Skeleton::Skeleton( Level* level )
|
||||
: super(level),
|
||||
bow(Item::bow, 1),
|
||||
fireCheckTick(0)
|
||||
{
|
||||
entityRendererId = ER_SKELETON_RENDERER;
|
||||
this->textureName = "mob/skeleton.png";
|
||||
}
|
||||
|
||||
int Skeleton::getMaxHealth() {
|
||||
return 10; // 15
|
||||
}
|
||||
|
||||
void Skeleton::aiStep() {
|
||||
if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) {
|
||||
float br = getBrightness(1);
|
||||
if (br > 0.5f) {
|
||||
if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) {
|
||||
hurt(NULL, 1);
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
|
||||
}
|
||||
//setOnFire(8); //@todo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super::aiStep();
|
||||
}
|
||||
|
||||
int Skeleton::getDeathLoot() {
|
||||
return Item::arrow->id;
|
||||
}
|
||||
|
||||
ItemInstance* Skeleton::getCarriedItem() {
|
||||
return &bow;
|
||||
}
|
||||
|
||||
int Skeleton::getEntityTypeId() const {
|
||||
return MobTypes::Skeleton;
|
||||
}
|
||||
|
||||
const char* Skeleton::getAmbientSound() {
|
||||
return "mob.skeleton";
|
||||
}
|
||||
|
||||
std::string Skeleton::getHurtSound() {
|
||||
return "mob.skeletonhurt";
|
||||
}
|
||||
|
||||
std::string Skeleton::getDeathSound() {
|
||||
return "mob.skeletonhurt";
|
||||
}
|
||||
|
||||
void Skeleton::checkHurtTarget( Entity* target, float d ) {
|
||||
if (d < 10) {
|
||||
float xd = target->x - x;
|
||||
float zd = target->z - z;
|
||||
|
||||
if (attackTime == 0) {
|
||||
Arrow* arrow = new Arrow(level, this, 1);
|
||||
// arrow.y += 1.4f;
|
||||
|
||||
float yd = (target->y + target->getHeadHeight() - 0.7f) - arrow->y;
|
||||
|
||||
float yo = Mth::sqrt(xd * xd + zd * zd) * 0.2f;
|
||||
|
||||
level->playSound(this, "random.bow", 1.0f, 1 / (random.nextFloat() * 0.4f + 0.8f));
|
||||
level->addEntity(arrow);
|
||||
|
||||
arrow->shoot(xd, yd + yo, zd, 1.60f, 32);
|
||||
attackTime = SharedConstants::TicksPerSecond * 3;
|
||||
}
|
||||
yRot = (float) (std::atan2(zd, xd) * Mth::RADDEG) - 90;
|
||||
|
||||
holdGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) {
|
||||
// drop some arrows
|
||||
int count = random.nextInt(3 /*+ playerBonusLevel*/);
|
||||
for (int i = 0; i < count; i++) {
|
||||
spawnAtLocation(Item::arrow->id, 1);
|
||||
}
|
||||
// and some bones
|
||||
count = random.nextInt(3 /*+ playerBonusLevel*/);
|
||||
for (int i = 0; i < count; i++) {
|
||||
spawnAtLocation(Item::bone->id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int Skeleton::getUseDuration() {
|
||||
return attackTime;
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
// MobType getMobType() {
|
||||
// return MobType.UNDEAD;
|
||||
// }
|
||||
43
src/world/entity/monster/Skeleton.h
Executable file
43
src/world/entity/monster/Skeleton.h
Executable file
@@ -0,0 +1,43 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Skeleton_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Skeleton_H__
|
||||
|
||||
//package net.minecraft.world.entity->monster;
|
||||
|
||||
#include "Monster.h"
|
||||
#include <string>
|
||||
#include "../../item/ItemInstance.h"
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
|
||||
class Skeleton: public Monster
|
||||
{
|
||||
typedef Monster super;
|
||||
public:
|
||||
Skeleton(Level* level);
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
void aiStep();
|
||||
|
||||
int getDeathLoot();
|
||||
|
||||
ItemInstance* getCarriedItem();
|
||||
|
||||
virtual int getEntityTypeId() const;
|
||||
protected:
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
void checkHurtTarget(Entity* target, float d);
|
||||
/*@Override*/
|
||||
void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/);
|
||||
virtual int getUseDuration();
|
||||
private:
|
||||
ItemInstance bow;
|
||||
int fireCheckTick;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Skeleton_H__*/
|
||||
137
src/world/entity/monster/Spider.cpp
Executable file
137
src/world/entity/monster/Spider.cpp
Executable file
@@ -0,0 +1,137 @@
|
||||
#include "Spider.h"
|
||||
#include "../../item/Item.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../util/Mth.h"
|
||||
|
||||
Spider::Spider( Level* level )
|
||||
: super(level),
|
||||
fireCheckTick(0)
|
||||
{
|
||||
entityRendererId = ER_SPIDER_RENDERER;
|
||||
this->textureName = "mob/spider.png";
|
||||
|
||||
this->setSize(1.4f, 0.9f);
|
||||
runSpeed = 0.5f;
|
||||
|
||||
entityData.define(DATA_FLAGS_ID, (DataFlagIdType) 0);
|
||||
}
|
||||
|
||||
void Spider::aiStep() {
|
||||
super::aiStep();
|
||||
}
|
||||
|
||||
void Spider::tick() {
|
||||
super::tick();
|
||||
|
||||
if (!level->isClientSide) {
|
||||
// this is to synchronize the spiders' climb state
|
||||
// in multiplayer (to stop them from "flashing")
|
||||
setClimbing(horizontalCollision);
|
||||
}
|
||||
}
|
||||
|
||||
int Spider::getMaxHealth() {
|
||||
return 8; // 12
|
||||
}
|
||||
|
||||
bool Spider::onLadder() {
|
||||
return isClimbing();
|
||||
}
|
||||
|
||||
void Spider::makeStuckInWeb() {
|
||||
// do nothing - spiders don't get stuck in web
|
||||
}
|
||||
|
||||
float Spider::getModelScale() {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool Spider::isClimbing() {
|
||||
return entityData.getFlag<DataFlagIdType>(DATA_FLAGS_ID, 0);
|
||||
}
|
||||
|
||||
void Spider::setClimbing( bool value ) {
|
||||
if (value)
|
||||
return entityData.setFlag<DataFlagIdType>(DATA_FLAGS_ID, 0);
|
||||
else
|
||||
return entityData.clearFlag<DataFlagIdType>(DATA_FLAGS_ID, 0);
|
||||
}
|
||||
|
||||
int Spider::getEntityTypeId() const {
|
||||
return MobTypes::Spider;
|
||||
}
|
||||
|
||||
bool Spider::makeStepSound() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity* Spider::findAttackTarget() {
|
||||
float br = getBrightness(1);
|
||||
if (br < 0.5f) {
|
||||
return level->getNearestPlayer(this, 16);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* Spider::getAmbientSound() {
|
||||
return "mob.spider";
|
||||
}
|
||||
|
||||
std::string Spider::getHurtSound() {
|
||||
return "mob.spider";
|
||||
}
|
||||
|
||||
std::string Spider::getDeathSound() {
|
||||
return "mob.spiderdeath";
|
||||
}
|
||||
|
||||
void Spider::checkHurtTarget( Entity* target, float d ) {
|
||||
float br = getBrightness(1);
|
||||
if (br > 0.5f && random.nextInt(100) == 0) {
|
||||
attackTargetId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (d > 2 && d < 6 && random.nextInt(10) == 0) {
|
||||
if (onGround) {
|
||||
float xdd = target->x - x;
|
||||
float zdd = target->z - z;
|
||||
float dd = Mth::sqrt(xdd * xdd + zdd * zdd);
|
||||
xd = (xdd / dd * 0.5f) * 0.8f + xd * 0.2f;
|
||||
zd = (zdd / dd * 0.5f) * 0.8f + zd * 0.2f;
|
||||
yd = 0.4f;
|
||||
}
|
||||
} else {
|
||||
super::checkHurtTarget(target, d);
|
||||
}
|
||||
}
|
||||
|
||||
int Spider::getDeathLoot() {
|
||||
return Item::string->id;
|
||||
}
|
||||
|
||||
//void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/) {
|
||||
// super::dropDeathLoot(/*wasKilledByPlayer, playerBonusLevel*/);
|
||||
|
||||
//// if (wasKilledByPlayer && (random.nextInt(3) == 0 || random.nextInt(1 + playerBonusLevel) > 0)) {
|
||||
//// spawnAtLocation(Item::spiderEye->id, 1);
|
||||
//// }
|
||||
//}
|
||||
|
||||
//float getRideHeight() {
|
||||
// return bbHeight * .75f - 0.5f;
|
||||
//}
|
||||
|
||||
/*@Override*/
|
||||
// MobType getMobType() {
|
||||
// return MobType.ARTHROPOD;
|
||||
// }
|
||||
|
||||
/*@Override*/ //@todo
|
||||
// bool canBeAffected(MobEffectInstance newEffect) {
|
||||
// if (newEffect.getId() == MobEffect.poison.id) {
|
||||
// return false;
|
||||
// }
|
||||
// return super::canBeAffected(newEffect);
|
||||
// }
|
||||
//
|
||||
62
src/world/entity/monster/Spider.h
Executable file
62
src/world/entity/monster/Spider.h
Executable file
@@ -0,0 +1,62 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Spider_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Spider_H__
|
||||
|
||||
//package net.minecraft.world.entity->monster;
|
||||
|
||||
#include "Monster.h"
|
||||
#include <string>
|
||||
|
||||
class Level;
|
||||
class Entity;
|
||||
|
||||
class Spider: public Monster
|
||||
{
|
||||
typedef Monster super;
|
||||
typedef SynchedEntityData::TypeChar DataFlagIdType;
|
||||
static const int DATA_FLAGS_ID = 16;
|
||||
public:
|
||||
Spider(Level* level);
|
||||
|
||||
/*@Override*/
|
||||
void aiStep();
|
||||
/*@Override*/
|
||||
void tick();
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
/**
|
||||
* The the spiders act as if they're always on a ladder, which enables them
|
||||
* to climb walls.
|
||||
*/
|
||||
/*@Override*/ //@todo
|
||||
bool onLadder();
|
||||
|
||||
/*@Override*/
|
||||
void makeStuckInWeb();
|
||||
|
||||
float getModelScale();
|
||||
|
||||
bool isClimbing();
|
||||
void setClimbing(bool value);
|
||||
|
||||
virtual int getEntityTypeId() const;
|
||||
|
||||
protected:
|
||||
/*@Override*/
|
||||
bool makeStepSound();
|
||||
|
||||
Entity* findAttackTarget();
|
||||
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
void checkHurtTarget(Entity* target, float d);
|
||||
int fireCheckTick;
|
||||
int getDeathLoot();
|
||||
/*@Override*/
|
||||
//void dropDeathLoot();
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Spider_H__*/
|
||||
129
src/world/entity/monster/Zombie.cpp
Executable file
129
src/world/entity/monster/Zombie.cpp
Executable file
@@ -0,0 +1,129 @@
|
||||
#include "Zombie.h"
|
||||
|
||||
#include "../../item/Item.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../util/Mth.h"
|
||||
//#include "../MobType.h"
|
||||
#include "../ai/goal/GoalSelector.h"
|
||||
#include "../ai/control/JumpControl.h"
|
||||
#include "../ai/goal/RandomStrollGoal.h"
|
||||
#include "../ai/goal/MeleeAttackGoal.h"
|
||||
#include "../ai/goal/target/NearestAttackableTargetGoal.h"
|
||||
#include "../ai/goal/target/HurtByTargetGoal.h"
|
||||
#include "../ai/goal/BreakDoorGoal.h"
|
||||
|
||||
Zombie::Zombie( Level* level )
|
||||
: super(level),
|
||||
fireCheckTick(0),
|
||||
_useNewAi(false)
|
||||
{
|
||||
entityRendererId = ER_ZOMBIE_RENDERER;
|
||||
this->textureName = "mob/zombie.png";
|
||||
//pathfinderMask |= CAN_OPEN_DOORS;
|
||||
//navigation->canOpenDoors = true;
|
||||
|
||||
runSpeed = 0.5f;
|
||||
attackDamage = 4;
|
||||
|
||||
targetSelector = new GoalSelector();
|
||||
targetSelector->addGoal(1, new HurtByTargetGoal(this, false));
|
||||
targetSelector->addGoal(2, new NearestAttackableTargetGoal(this, 1, 16, 0, true));
|
||||
|
||||
goalSelector = new GoalSelector();
|
||||
//goalSelector->addGoal(1, new BreakDoorGoal(this));
|
||||
goalSelector->addGoal(2, new MeleeAttackGoal(this, runSpeed, false, 0));
|
||||
goalSelector->addGoal(7, new RandomStrollGoal(this, runSpeed) );
|
||||
|
||||
moveControl = new MoveControl(this);
|
||||
jumpControl = new JumpControl(this);
|
||||
}
|
||||
|
||||
Zombie::~Zombie() {
|
||||
delete goalSelector;
|
||||
delete targetSelector;
|
||||
|
||||
delete moveControl;
|
||||
delete jumpControl;
|
||||
}
|
||||
|
||||
int Zombie::getMaxHealth() {
|
||||
return 12; // 16
|
||||
}
|
||||
|
||||
void Zombie::aiStep() {
|
||||
if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) {
|
||||
float br = getBrightness(1);
|
||||
if (br > 0.5f) {
|
||||
if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) {
|
||||
hurt(NULL, 1);
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f;
|
||||
level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za);
|
||||
}
|
||||
//setOnFire(8); //@todo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super::aiStep();
|
||||
}
|
||||
|
||||
int Zombie::getEntityTypeId() const {
|
||||
return MobTypes::Zombie;
|
||||
}
|
||||
|
||||
void Zombie::setUseNewAi( bool use ) {
|
||||
_useNewAi = use;
|
||||
}
|
||||
|
||||
int Zombie::getArmorValue() {
|
||||
int armor = super::getArmorValue() + 2;
|
||||
if (armor > 20) armor = 20;
|
||||
return armor;
|
||||
}
|
||||
|
||||
const char* Zombie::getAmbientSound() {
|
||||
return "mob.zombie";
|
||||
}
|
||||
|
||||
std::string Zombie::getHurtSound() {
|
||||
return "mob.zombiehurt";
|
||||
}
|
||||
|
||||
std::string Zombie::getDeathSound() {
|
||||
return "mob.zombiedeath";
|
||||
}
|
||||
|
||||
int Zombie::getDeathLoot() {
|
||||
return 0; //@todo
|
||||
//return Item::rotten_flesh->id;
|
||||
}
|
||||
|
||||
bool Zombie::useNewAi() {
|
||||
return _useNewAi;
|
||||
}
|
||||
|
||||
void Zombie::die( Entity* source ) {
|
||||
super::die(source);
|
||||
if(!level->isClientSide) {
|
||||
if(random.nextInt(4) == 0) {
|
||||
spawnAtLocation(Item::feather->id, random.nextInt(1) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Zombie::getAttackDamage( Entity* target ) {
|
||||
ItemInstance* weapon = getCarriedItem();
|
||||
int damage = attackDamage;
|
||||
if(weapon != NULL) damage += weapon->getAttackDamage(this);
|
||||
return damage;
|
||||
}
|
||||
|
||||
/*@Override*/ //@todo?
|
||||
//MobType getMobType() {
|
||||
// return MobType::UNDEAD;
|
||||
//}
|
||||
|
||||
44
src/world/entity/monster/Zombie.h
Executable file
44
src/world/entity/monster/Zombie.h
Executable file
@@ -0,0 +1,44 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Zombie_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Zombie_H__
|
||||
|
||||
//package net.minecraft.world.entity->monster;
|
||||
|
||||
#include "Monster.h"
|
||||
#include <string>
|
||||
|
||||
class Level;
|
||||
|
||||
class Zombie: public Monster
|
||||
{
|
||||
typedef Monster super;
|
||||
public:
|
||||
Zombie(Level* level);
|
||||
|
||||
~Zombie();
|
||||
|
||||
/*@Override*/
|
||||
int getMaxHealth();
|
||||
|
||||
void aiStep();
|
||||
virtual int getEntityTypeId() const;
|
||||
void setUseNewAi(bool use);
|
||||
virtual void die(Entity* source);
|
||||
virtual int getAttackDamage(Entity* target);
|
||||
protected:
|
||||
/*@Override*/
|
||||
int getArmorValue();
|
||||
|
||||
const char* getAmbientSound();
|
||||
std::string getHurtSound();
|
||||
std::string getDeathSound();
|
||||
|
||||
//@todo
|
||||
int getDeathLoot();
|
||||
|
||||
virtual bool useNewAi();
|
||||
|
||||
int fireCheckTick;
|
||||
bool _useNewAi;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Zombie_H__*/
|
||||
47
src/world/entity/player/Abilities.h
Executable file
47
src/world/entity/player/Abilities.h
Executable file
@@ -0,0 +1,47 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PLAYER__Abilities_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PLAYER__Abilities_H__
|
||||
|
||||
//package net.minecraft.world.entity.player;
|
||||
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
class Abilities
|
||||
{
|
||||
public:
|
||||
Abilities()
|
||||
: invulnerable(false),
|
||||
flying(false),
|
||||
mayfly(false),
|
||||
instabuild(false)
|
||||
{
|
||||
}
|
||||
|
||||
void addSaveData(CompoundTag* parentTag) {
|
||||
CompoundTag* tag = new CompoundTag();
|
||||
|
||||
tag->putBoolean("invulnerable", invulnerable);
|
||||
tag->putBoolean("flying", invulnerable);
|
||||
tag->putBoolean("mayfly", mayfly);
|
||||
tag->putBoolean("instabuild", instabuild);
|
||||
|
||||
parentTag->put("abilities", tag);
|
||||
}
|
||||
|
||||
void loadSaveData(CompoundTag* parentTag) {
|
||||
if (parentTag->contains("abilities")) {
|
||||
CompoundTag* tag = parentTag->getCompound("abilities");
|
||||
|
||||
invulnerable = tag->getBoolean("invulnerable");
|
||||
flying = tag->getBoolean("flying");
|
||||
mayfly = tag->getBoolean("mayfly");
|
||||
instabuild = tag->getBoolean("instabuild");
|
||||
}
|
||||
}
|
||||
|
||||
bool invulnerable;
|
||||
bool flying;
|
||||
bool mayfly;
|
||||
bool instabuild;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PLAYER__Abilities_H__*/
|
||||
359
src/world/entity/player/Inventory.cpp
Executable file
359
src/world/entity/player/Inventory.cpp
Executable file
@@ -0,0 +1,359 @@
|
||||
#include "Inventory.h"
|
||||
#include "../../level/material/Material.h"
|
||||
#include "../../level/tile/QuartzBlockTile.h"
|
||||
#include "../../level/tile/TreeTile.h"
|
||||
#include "../../level/tile/StoneSlabTile.h"
|
||||
#include "../../item/DyePowderItem.h"
|
||||
#include "../../item/crafting/Recipe.h"
|
||||
#include "../../item/CoalItem.h"
|
||||
#include "../../level/tile/SandStoneTile.h"
|
||||
|
||||
Inventory::Inventory( Player* player, bool creativeMode )
|
||||
: super( 36 + Inventory::MAX_SELECTION_SIZE,
|
||||
MAX_SELECTION_SIZE,
|
||||
ContainerType::INVENTORY,
|
||||
creativeMode),
|
||||
player(player),
|
||||
selected(0)
|
||||
{
|
||||
setupDefault();
|
||||
compressLinkedSlotList(0);
|
||||
}
|
||||
|
||||
Inventory::~Inventory() {
|
||||
}
|
||||
|
||||
ItemInstance* Inventory::getSelected() {
|
||||
return getLinked(selected);
|
||||
}
|
||||
|
||||
void Inventory::selectSlot( int slot ) {
|
||||
if (slot < MAX_SELECTION_SIZE && slot >= 0)
|
||||
selected = slot;
|
||||
}
|
||||
|
||||
bool Inventory::moveToSelectedSlot( int inventorySlot, bool propagate ) {
|
||||
return linkSlot(selected, inventorySlot, propagate);
|
||||
}
|
||||
|
||||
int Inventory::getSelectionSize() {
|
||||
return MAX_SELECTION_SIZE;
|
||||
}
|
||||
|
||||
void Inventory::setupDefault() {
|
||||
clearInventory();
|
||||
int Sel[MAX_SELECTION_SIZE] = {0};
|
||||
|
||||
#ifdef DEMO_MODE
|
||||
if (_isCreative) {
|
||||
Sel[0] = addItem(new ItemInstance(Item::shovel_stone));
|
||||
addItem(new ItemInstance(Item::pickAxe_stone));
|
||||
addItem(new ItemInstance(Item::hatchet_stone));
|
||||
addItem(new ItemInstance((Item*)Item::shears));
|
||||
addItem(new ItemInstance(Tile::ladder));
|
||||
Sel[3] = addItem(new ItemInstance(Tile::torch));
|
||||
addItem(new ItemInstance(Item::door_wood));
|
||||
|
||||
Sel[4] = addItem(new ItemInstance(Tile::stoneBrick));
|
||||
Sel[5] = addItem(new ItemInstance(Tile::wood));
|
||||
Sel[2] = addItem(new ItemInstance(Tile::redBrick));
|
||||
Sel[1] = addItem(new ItemInstance(Tile::dirt));
|
||||
addItem(new ItemInstance(Tile::sandStone));
|
||||
addItem(new ItemInstance(Tile::gravel));
|
||||
addItem(new ItemInstance(Tile::rock));
|
||||
addItem(new ItemInstance(Tile::sand));
|
||||
//addItem(new ItemInstance(Tile::clay));
|
||||
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 15));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 14));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 13));
|
||||
Sel[7] = addItem(new ItemInstance(Tile::cloth, 1, 12));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 11));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 10));
|
||||
Sel[8] = addItem(new ItemInstance(Tile::cloth, 1, 9));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 8));
|
||||
Sel[6] = addItem(new ItemInstance(Tile::glass));
|
||||
addItem(new ItemInstance(Tile::thinGlass));
|
||||
addItem(new ItemInstance(Tile::stairs_stone));
|
||||
addItem(new ItemInstance(Tile::bookshelf));
|
||||
addItem(new ItemInstance(Tile::workBench));
|
||||
addItem(new ItemInstance(Tile::chest));
|
||||
addItem(new ItemInstance(Tile::furnace));
|
||||
|
||||
addItem(new ItemInstance(((Tile*)Tile::flower)));
|
||||
addItem(new ItemInstance(Tile::cactus));
|
||||
|
||||
//
|
||||
// Those below are inactive due to demo
|
||||
//
|
||||
addItem(new ItemInstance(Item::sword_stone));
|
||||
addItem(new ItemInstance(Tile::treeTrunk, 1, 0));
|
||||
addItem(new ItemInstance(Tile::treeTrunk, 1, 1));
|
||||
addItem(new ItemInstance(Tile::treeTrunk, 1, 2));
|
||||
addItem(new ItemInstance(Tile::fence));
|
||||
addItem(new ItemInstance(Tile::fenceGate));
|
||||
addItem(new ItemInstance(Item::reeds));
|
||||
addItem(new ItemInstance(((Tile*)Tile::rose)));
|
||||
addItem(new ItemInstance(((Tile*)Tile::mushroom2)));
|
||||
addItem(new ItemInstance(((Tile*)Tile::mushroom1)));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 7));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 6));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 5));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 4));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 3));
|
||||
addItem(new ItemInstance(Tile::stairs_wood));
|
||||
addItem(new ItemInstance(Tile::goldBlock));
|
||||
addItem(new ItemInstance(Tile::ironBlock));
|
||||
addItem(new ItemInstance(Tile::emeraldBlock));
|
||||
addItem(new ItemInstance(Tile::lapisBlock));
|
||||
addItem(new ItemInstance(Tile::obsidian));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf));
|
||||
} else {
|
||||
#if defined(WIN32)
|
||||
// Survival
|
||||
addItem(new ItemInstance((Item*)Item::shears));
|
||||
addItem(new ItemInstance(Tile::redBrick));
|
||||
addItem(new ItemInstance(Tile::glass));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (_isCreative) {
|
||||
// Blocks
|
||||
Sel[1] = addItem(new ItemInstance(Tile::stoneBrick));
|
||||
addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 0));
|
||||
addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 1));
|
||||
addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 2));
|
||||
addItem(new ItemInstance(Tile::mossStone));
|
||||
Sel[5] = addItem(new ItemInstance(Tile::wood));
|
||||
Sel[2] = addItem(new ItemInstance(Tile::redBrick));
|
||||
|
||||
#ifdef RPI
|
||||
Sel[3] = addItem(new ItemInstance(Tile::rock));
|
||||
#else
|
||||
Sel[0] = addItem(new ItemInstance(Tile::rock));
|
||||
#endif
|
||||
Sel[4] = addItem(new ItemInstance(Tile::dirt));
|
||||
addItem(new ItemInstance(Tile::grass));
|
||||
addItem(new ItemInstance(Tile::clay));
|
||||
addItem(new ItemInstance(Tile::sandStone, 1, 0));
|
||||
addItem(new ItemInstance(Tile::sandStone, 1, 1));
|
||||
addItem(new ItemInstance(Tile::sandStone, 1, 2));
|
||||
addItem(new ItemInstance(Tile::sand));
|
||||
addItem(new ItemInstance(Tile::gravel));
|
||||
|
||||
Sel[7] = addItem(new ItemInstance(Tile::treeTrunk, 1, 0));
|
||||
addItem(new ItemInstance(Tile::treeTrunk, 1, 1));
|
||||
addItem(new ItemInstance(Tile::treeTrunk, 1, 2));
|
||||
addItem(new ItemInstance(Tile::netherBrick));
|
||||
addItem(new ItemInstance(Tile::netherrack));
|
||||
addItem(new ItemInstance(Tile::stairs_stone));
|
||||
addItem(new ItemInstance(Tile::stairs_wood));
|
||||
Sel[6] = addItem(new ItemInstance(Tile::stairs_brick));
|
||||
addItem(new ItemInstance(Tile::stairs_sandStone));
|
||||
addItem(new ItemInstance(Tile::stairs_stoneBrickSmooth));
|
||||
addItem(new ItemInstance(Tile::stairs_netherBricks));
|
||||
addItem(new ItemInstance(Tile::stairs_quartz));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::STONE_SLAB));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::COBBLESTONE_SLAB));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::WOOD_SLAB));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::BRICK_SLAB));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SAND_SLAB));
|
||||
addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SMOOTHBRICK_SLAB));
|
||||
|
||||
addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_DEFAULT));
|
||||
addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_LINES));
|
||||
addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_CHISELED));
|
||||
|
||||
|
||||
|
||||
// Ores
|
||||
addItem(new ItemInstance(Tile::coalOre));
|
||||
addItem(new ItemInstance(Tile::ironOre));
|
||||
addItem(new ItemInstance(Tile::goldOre));
|
||||
addItem(new ItemInstance(Tile::emeraldOre));
|
||||
addItem(new ItemInstance(Tile::lapisOre));
|
||||
addItem(new ItemInstance(Tile::redStoneOre));
|
||||
|
||||
addItem(new ItemInstance(Tile::goldBlock));
|
||||
addItem(new ItemInstance(Tile::ironBlock));
|
||||
addItem(new ItemInstance(Tile::emeraldBlock));
|
||||
addItem(new ItemInstance(Tile::lapisBlock));
|
||||
addItem(new ItemInstance(Tile::obsidian));
|
||||
addItem(new ItemInstance(Tile::snow));
|
||||
addItem(new ItemInstance(Tile::glass));
|
||||
addItem(new ItemInstance(Tile::lightGem));
|
||||
|
||||
addItem(new ItemInstance(Tile::netherReactor));
|
||||
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 0));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 7));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 6));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 5));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 4));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 3));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 2));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 1));
|
||||
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 15));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 14));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 13));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 12));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 11));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 10));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 9));
|
||||
addItem(new ItemInstance(Tile::cloth, 1, 8));
|
||||
addItem(new ItemInstance(Tile::ladder));
|
||||
#ifdef RPI
|
||||
addItem(new ItemInstance(Tile::torch));
|
||||
#else
|
||||
Sel[3] = addItem(new ItemInstance(Tile::torch));
|
||||
#endif
|
||||
addItem(new ItemInstance(Tile::thinGlass));
|
||||
|
||||
addItem(new ItemInstance(Item::door_wood));
|
||||
addItem(new ItemInstance(Tile::trapdoor));
|
||||
addItem(new ItemInstance(Tile::fence));
|
||||
addItem(new ItemInstance(Tile::fenceGate));
|
||||
|
||||
addItem(new ItemInstance(Item::bed));
|
||||
addItem(new ItemInstance(Tile::bookshelf));
|
||||
addItem(new ItemInstance(Item::painting));
|
||||
addItem(new ItemInstance(Tile::workBench));
|
||||
addItem(new ItemInstance(Tile::stonecutterBench));
|
||||
addItem(new ItemInstance(Tile::chest));
|
||||
addItem(new ItemInstance(Tile::furnace));
|
||||
addItem(new ItemInstance(Tile::tnt));
|
||||
|
||||
addItem(new ItemInstance(((Tile*)Tile::flower)));
|
||||
addItem(new ItemInstance(((Tile*)Tile::rose)));
|
||||
addItem(new ItemInstance(((Tile*)Tile::mushroom1)));
|
||||
addItem(new ItemInstance(((Tile*)Tile::mushroom2)));
|
||||
addItem(new ItemInstance(Tile::cactus));
|
||||
addItem(new ItemInstance(Tile::melon));
|
||||
addItem(new ItemInstance(Item::reeds));
|
||||
Sel[8] = addItem(new ItemInstance(Tile::sapling, 1, 0));
|
||||
addItem(new ItemInstance(Tile::sapling, 1, 1));
|
||||
addItem(new ItemInstance(Tile::sapling, 1, 2));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1));
|
||||
addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2));
|
||||
|
||||
addItem(new ItemInstance(Item::seeds_wheat));
|
||||
addItem(new ItemInstance(Item::seeds_melon));
|
||||
addItem(new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE));
|
||||
addItem(new ItemInstance(Item::hoe_iron));
|
||||
#ifdef RPI
|
||||
Sel[0] = addItem(new ItemInstance(Item::sword_iron));
|
||||
#else
|
||||
addItem(new ItemInstance(Item::sword_iron));
|
||||
#endif
|
||||
addItem(new ItemInstance(Item::bow));
|
||||
addItem(new ItemInstance(Item::sign));
|
||||
} else {
|
||||
#if defined(WIN32)
|
||||
// Survival
|
||||
addItem(new ItemInstance(Item::ironIngot, 64));
|
||||
addItem(new ItemInstance(Item::ironIngot, 34));
|
||||
addItem(new ItemInstance(Tile::stonecutterBench));
|
||||
addItem(new ItemInstance(Tile::workBench));
|
||||
addItem(new ItemInstance(Tile::furnace));
|
||||
addItem(new ItemInstance(Tile::wood, 54));
|
||||
addItem(new ItemInstance(Item::stick, 14));
|
||||
addItem(new ItemInstance(Item::coal, 31));
|
||||
addItem(new ItemInstance(Tile::sand, 6));
|
||||
addItem(new ItemInstance(Item::dye_powder, 23, DyePowderItem::PURPLE));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0; i < items.size(); ++i) {
|
||||
ItemInstance* item = items[i];
|
||||
|
||||
if (i < MAX_SELECTION_SIZE) {
|
||||
if (item)
|
||||
LOGE("Error: Should not have items on slot %i\n", i);
|
||||
|
||||
items[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item && _isCreative)
|
||||
item->count = 5;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SELECTION_SIZE; ++i) {
|
||||
linkedSlots[i] = LinkedSlot(Sel[i]);
|
||||
}
|
||||
|
||||
//LOGI("Inventory has %d items\n", (int)items.size());
|
||||
}
|
||||
|
||||
void Inventory::clearInventoryWithDefault()
|
||||
{
|
||||
clearInventory();
|
||||
setupDefault();
|
||||
}
|
||||
|
||||
int Inventory::getAttackDamage( Entity* entity )
|
||||
{
|
||||
ItemInstance* item = getSelected();
|
||||
if (item != NULL) return item->getAttackDamage(entity);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool Inventory::canDestroy( Tile* tile )
|
||||
{
|
||||
if (tile->material->isAlwaysDestroyable()) return true;
|
||||
|
||||
ItemInstance* item = getSelected();
|
||||
if (item != NULL) return item->canDestroySpecial(tile);
|
||||
return false;
|
||||
}
|
||||
|
||||
float Inventory::getDestroySpeed( Tile* tile )
|
||||
{
|
||||
ItemInstance* item = getSelected();
|
||||
if (item && item->id >= 256) {
|
||||
return Item::items[item->id]->getDestroySpeed(NULL, tile);
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool Inventory::moveToSelectionSlot( int selectionSlot, int inventorySlot, bool propagate ) {
|
||||
return linkSlot(selectionSlot, inventorySlot, propagate);
|
||||
}
|
||||
|
||||
bool Inventory::moveToEmptySelectionSlot( int inventorySlot ) {
|
||||
return linkEmptySlot(inventorySlot);
|
||||
}
|
||||
|
||||
void Inventory::doDrop( ItemInstance* item, bool randomly )
|
||||
{
|
||||
player->drop(item, randomly);
|
||||
}
|
||||
|
||||
bool Inventory::stillValid(Player* player) {
|
||||
if (this->player->removed) return false;
|
||||
if (player->distanceToSqr(this->player) > 8 * 8) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Inventory::add( ItemInstance* item ){
|
||||
if (_isCreative || player->hasFakeInventory)
|
||||
return true;
|
||||
|
||||
return super::add(item);
|
||||
}
|
||||
|
||||
bool Inventory::removeItem( const ItemInstance* samePtr ) {
|
||||
for (int i = MAX_SELECTION_SIZE; i < (int)items.size(); ++i) {
|
||||
if (items[i] == samePtr) {
|
||||
clearSlot(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
57
src/world/entity/player/Inventory.h
Executable file
57
src/world/entity/player/Inventory.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PLAYER__JInventory_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PLAYER__JInventory_H__
|
||||
|
||||
//package net.minecraft.world.entity.player;
|
||||
|
||||
#include "../../inventory/FillingContainer.h"
|
||||
#include <vector>
|
||||
|
||||
class Tile;
|
||||
class Entity;
|
||||
class Player;
|
||||
class ListTag;
|
||||
class CompoundTag;
|
||||
|
||||
class Inventory: public FillingContainer
|
||||
{
|
||||
typedef FillingContainer super;
|
||||
public:
|
||||
static const int INVENTORY_SIZE_DEMO = 27;
|
||||
static const int MAX_SELECTION_SIZE = 9; // Including "More..." right now
|
||||
static const int POP_TIME_DURATION = 5;
|
||||
|
||||
Inventory(Player* player, bool creativeMode);
|
||||
~Inventory();
|
||||
|
||||
void clearInventoryWithDefault();
|
||||
//
|
||||
// Selection slots
|
||||
//
|
||||
void selectSlot(int slot);
|
||||
ItemInstance* getSelected();
|
||||
|
||||
static int getSelectionSize();
|
||||
// Special for this "selection based" inventory
|
||||
bool moveToSelectionSlot(int selectionSlot, int inventorySlot, bool propagate);
|
||||
bool moveToSelectedSlot(int inventorySlot, bool propagate);
|
||||
bool moveToEmptySelectionSlot(int inventorySlot);
|
||||
|
||||
bool removeItem(const ItemInstance* samePtr);
|
||||
|
||||
void doDrop(ItemInstance* item, bool randomly);
|
||||
bool stillValid(Player* player);
|
||||
bool add(ItemInstance* item);
|
||||
|
||||
int getAttackDamage(Entity* entity);
|
||||
float getDestroySpeed(Tile* tile);
|
||||
bool canDestroy(Tile* tile);
|
||||
private:
|
||||
void setupDefault();
|
||||
public:
|
||||
//ItemList armor;
|
||||
|
||||
int selected;
|
||||
Player* player;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PLAYER__JInventory_H__*/
|
||||
9
src/world/entity/player/InventorySlotManager.h
Executable file
9
src/world/entity/player/InventorySlotManager.h
Executable file
@@ -0,0 +1,9 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PLAYER__InventorySlotManager_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PLAYER__InventorySlotManager_H__
|
||||
|
||||
//package net.minecraft.world.entity.player;
|
||||
|
||||
class InventorySlotManager {
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PLAYER__InventorySlotManager_H__*/
|
||||
44
src/world/entity/player/OldInventory.h
Executable file
44
src/world/entity/player/OldInventory.h
Executable file
@@ -0,0 +1,44 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PLAYER__Inventory_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PLAYER__Inventory_H__
|
||||
|
||||
//package net.minecraft.world.entity.player;
|
||||
|
||||
class Player;
|
||||
class Tile;
|
||||
|
||||
class Inventory
|
||||
{
|
||||
public:
|
||||
static const int POP_TIME_DURATION = 5;
|
||||
static const int MAX_SELECTION_SIZE = 9; // Including "More..." right now
|
||||
|
||||
static const int INVENTORY_ROWS = 5;
|
||||
static const int INVENTORY_COLS = 9;
|
||||
static const int INVENTORY_SIZE = INVENTORY_COLS * INVENTORY_ROWS;
|
||||
static const int INVENTORY_SIZE_DEMO = 18;
|
||||
|
||||
Inventory(Player* player_);
|
||||
|
||||
void selectSlot(int slot);
|
||||
|
||||
int getSelectedItemId();
|
||||
int getSelectionSlotItemId(int slot);
|
||||
|
||||
void setSelectionSlotItemId(int slot, int id);
|
||||
|
||||
float getDestroySpeed(Tile* tile);
|
||||
|
||||
|
||||
//int getCurrentSelectionSize();
|
||||
//void setCurrentSelectionSize(int size) { _selectionSize = size; }
|
||||
|
||||
int selected;
|
||||
protected:
|
||||
//int _selectionSize;
|
||||
Player* player;
|
||||
|
||||
int itemIds[MAX_SELECTION_SIZE];
|
||||
int inventoryIds[INVENTORY_SIZE];
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PLAYER__Inventory_H__*/
|
||||
924
src/world/entity/player/Player.cpp
Executable file
924
src/world/entity/player/Player.cpp
Executable file
@@ -0,0 +1,924 @@
|
||||
#include "Player.h"
|
||||
#include "Inventory.h"
|
||||
#include "../item/ItemEntity.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../item/ItemInstance.h"
|
||||
#include "../../item/BowItem.h"
|
||||
#include "../../inventory/BaseContainerMenu.h"
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
#include "../../../network/RakNetInstance.h"
|
||||
#include "../../../network/packet/AnimatePacket.h"
|
||||
#include "../../inventory/FurnaceMenu.h"
|
||||
#include "../SharedFlags.h"
|
||||
#include "../../level/tile/BedTile.h"
|
||||
#include "../../Direction.h"
|
||||
#include "../EntityEvent.h"
|
||||
#include "../../Difficulty.h"
|
||||
#include "../../item/ArmorItem.h"
|
||||
|
||||
const float Player::DEFAULT_WALK_SPEED = 0.1f;
|
||||
const float Player::DEFAULT_FLY_SPEED = 0.02f;
|
||||
|
||||
// @todo: Move out to ArmorInventory
|
||||
static ListTag* saveArmor(ItemInstance* armor);
|
||||
static void loadArmor(ItemInstance* armor, ListTag* listTag);
|
||||
|
||||
Player::Player(Level* level, bool isCreative)
|
||||
: super(level),
|
||||
userType(0),
|
||||
playerHasRespawnPosition(false),
|
||||
hasFakeInventory(false),
|
||||
containerMenu(NULL),
|
||||
useItemDuration(0),
|
||||
playerIsSleeping(false),
|
||||
sleepCounter(0),
|
||||
bedOffsetX(0),
|
||||
bedOffsetY(0),
|
||||
bedOffsetZ(0),
|
||||
respawnPosition(0, -1, 0),
|
||||
allPlayersSleeping(false)
|
||||
{
|
||||
canRemove = false;
|
||||
|
||||
_init();
|
||||
entityRendererId = ER_PLAYER_RENDERER;
|
||||
|
||||
autoSendPosRot = false;
|
||||
inventory = new Inventory(this, isCreative);
|
||||
|
||||
//inventoryMenu = /*new*/ InventoryMenu(inventory, !level.isOnline);
|
||||
//containerMenu = inventoryMenu;
|
||||
|
||||
heightOffset = 1.62f;
|
||||
|
||||
Pos spawnPos = level->getSharedSpawnPos();
|
||||
this->moveTo((float)spawnPos.x + 0.5f, (float)(spawnPos.y + 1), (float)spawnPos.z + 0.5f, 0, 0);
|
||||
|
||||
health = MAX_HEALTH;
|
||||
modelName = "humanoid";
|
||||
rotOffs = 180;
|
||||
flameTime = 20;
|
||||
|
||||
textureName = "mob/char.png";
|
||||
entityData.define(DATA_PLAYER_FLAGS_ID, (PlayerFlagIDType) 0);
|
||||
entityData.define(DATA_BED_POSITION_ID, Pos());
|
||||
//entityData.define(DATA_PLAYER_RUNNING_ID, (SynchedEntityData::TypeChar) 0);
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
delete inventory;
|
||||
}
|
||||
bool Player::isSleeping() {
|
||||
return playerIsSleeping;
|
||||
}
|
||||
int Player::startSleepInBed( int x, int y, int z ) {
|
||||
if(!level->isClientSide) {
|
||||
if(isSleeping() || !isAlive()) {
|
||||
return BedSleepingResult::OTHER_PROBLEM;
|
||||
}
|
||||
if(Mth::abs(this->x - x) > 3 || Mth::abs(this->y - y) > 4 || Mth::abs(this->z - z) > 3) {
|
||||
return BedSleepingResult::TOO_FAR_AWAY;
|
||||
}
|
||||
if(level->dimension->isNaturalDimension()) {
|
||||
return BedSleepingResult::NOT_POSSIBLE_HERE;
|
||||
}
|
||||
if(level->isDay()) {
|
||||
return BedSleepingResult::NOT_POSSIBLE_NOW;
|
||||
}
|
||||
float hRange = 8;
|
||||
float vRange = 5;
|
||||
EntityList monsters;
|
||||
level->getEntitiesOfClass(MobTypes::BaseEnemy, AABB(x- hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange), monsters);
|
||||
if(!monsters.empty()) {
|
||||
return BedSleepingResult::NOT_SAFE;
|
||||
}
|
||||
}
|
||||
|
||||
setSize(0.2f, 0.2f);
|
||||
heightOffset = 0.2f;
|
||||
if(level->hasChunkAt(x, y, z)) {
|
||||
int data = level->getData(x, y, z);
|
||||
int direction = BedTile::getDirection(data);
|
||||
float xo = 0.5f, zo = 0.5f;
|
||||
switch(direction) {
|
||||
case Direction::SOUTH:
|
||||
zo = 0.9f;
|
||||
break;
|
||||
case Direction::NORTH:
|
||||
zo = 0.1f;
|
||||
break;
|
||||
case Direction::WEST:
|
||||
xo = 0.1f;
|
||||
break;
|
||||
case Direction::EAST:
|
||||
xo = 0.9f;
|
||||
break;
|
||||
}
|
||||
setBedOffset(direction);
|
||||
setPos(x + xo, y + 15.0f / 16.0f, z + zo);
|
||||
} else {
|
||||
setPos(x + 0.5f, y + 1.0f / 16.0f, z + 0.5f);
|
||||
}
|
||||
playerIsSleeping = true;
|
||||
sleepCounter = 0;
|
||||
bedPosition = Pos(x, y, z);
|
||||
xd = zd = yd = 0;
|
||||
if(!level->isClientSide) {
|
||||
level->updateSleepingPlayerList();
|
||||
}
|
||||
entityData.set<Pos>(DATA_BED_POSITION_ID, bedPosition);
|
||||
entityData.setFlag<SharedFlagsInformation::SharedFlagsInformationType>(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG);
|
||||
return BedSleepingResult::OK;
|
||||
}
|
||||
|
||||
void Player::stopSleepInBed( bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint ) {
|
||||
if(!isSleeping())
|
||||
return;
|
||||
setSize(0.6f, 1.8f);
|
||||
setDefaultHeadHeight();
|
||||
Pos standUp = bedPosition;
|
||||
if(level->getTile(int(bedPosition.x), int(bedPosition.y), int(bedPosition.z)) == Tile::bed->id) {
|
||||
BedTile::setOccupied(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), false);
|
||||
bool foundStandUpPosition = BedTile::findStandUpPosition(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), 0, standUp);
|
||||
if(!foundStandUpPosition) {
|
||||
standUp = Pos(bedPosition.x, bedPosition.y, bedPosition.z);
|
||||
}
|
||||
setPos(standUp.x + 0.5f, standUp.y + heightOffset + 0.1f, standUp.z + 0.5f);
|
||||
}
|
||||
playerIsSleeping = false;
|
||||
if(!level->isClientSide && updateLevelList) {
|
||||
level->updateSleepingPlayerList();
|
||||
}
|
||||
if(forcefulWakeUp) {
|
||||
sleepCounter = 0;
|
||||
} else {
|
||||
sleepCounter = SLEEP_DURATION;
|
||||
}
|
||||
// Quick fix to make the spawn position always saved, not sure if we always want to save this position but I like it.
|
||||
if(true || saveRespawnPoint) {
|
||||
Pos newRespawnPos;
|
||||
BedTile::findStandUpPosition(level, bedPosition.x, bedPosition.y, bedPosition.z, 0, newRespawnPos);
|
||||
setRespawnPosition(newRespawnPos);
|
||||
}
|
||||
entityData.clearFlag<SharedFlagsInformation::SharedFlagsInformationType>(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG);
|
||||
allPlayersSleeping = false;
|
||||
}
|
||||
|
||||
int Player::getSleepTimer() {
|
||||
return allPlayersSleeping ? sleepCounter : 0;
|
||||
}
|
||||
void Player::setAllPlayersSleeping() {
|
||||
sleepCounter = 0;
|
||||
allPlayersSleeping = true;
|
||||
}
|
||||
void Player::setBedOffset( int bedDirection ) {
|
||||
bedOffsetX = 0;
|
||||
bedOffsetZ = 0;
|
||||
switch(bedDirection) {
|
||||
case Direction::SOUTH:
|
||||
bedOffsetZ = -1.8f;
|
||||
break;
|
||||
case Direction::NORTH:
|
||||
bedOffsetZ = 1.8f;
|
||||
break;
|
||||
case Direction::WEST:
|
||||
bedOffsetX = 1.8f;
|
||||
break;
|
||||
case Direction::EAST:
|
||||
bedOffsetX = -1.8f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool Player::isSleepingLongEnough() {
|
||||
return isSleeping() && sleepCounter >= SLEEP_DURATION;
|
||||
}
|
||||
|
||||
float Player::getSleepRotation() {
|
||||
if(isSleeping()) {
|
||||
int data = level->getData(bedPosition.x, bedPosition.y, bedPosition.z);
|
||||
int direction = BedTile::getDirection(data);
|
||||
switch(direction) {
|
||||
case Direction::SOUTH:
|
||||
return 90;
|
||||
case Direction::WEST:
|
||||
return 0;
|
||||
case Direction::NORTH:
|
||||
return 270;
|
||||
case Direction::EAST:
|
||||
return 180;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Player::checkBed() {
|
||||
return (level->getTile(bedPosition.x, bedPosition.y, bedPosition.z) == Tile::bed->id);
|
||||
}
|
||||
|
||||
void Player::tick() {
|
||||
bool shouldSleep = entityData.getFlag<SharedFlagsInformation::SharedFlagsInformationType>(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG);
|
||||
if(shouldSleep != isSleeping()) {
|
||||
if(isSleeping()) {
|
||||
stopSleepInBed(true, true, true);
|
||||
} else {
|
||||
bedPosition = entityData.getPos(DATA_BED_POSITION_ID);
|
||||
startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z);
|
||||
}
|
||||
}
|
||||
if(isSleeping()) {
|
||||
sleepCounter++;
|
||||
if(sleepCounter > SLEEP_DURATION) {
|
||||
sleepCounter = SLEEP_DURATION;
|
||||
}
|
||||
if(!level->isClientSide) {
|
||||
if(!checkBed()) {
|
||||
stopSleepInBed(true, true, false);
|
||||
} else if(level->isDay()) {
|
||||
stopSleepInBed(false, true, true);
|
||||
}
|
||||
}
|
||||
} else if(sleepCounter > 0) {
|
||||
sleepCounter++;
|
||||
if(sleepCounter >= (SLEEP_DURATION + WAKE_UP_DURATION)) {
|
||||
sleepCounter = 0;
|
||||
}
|
||||
}
|
||||
super::tick();
|
||||
|
||||
if (!level->isClientSide) {
|
||||
foodData.tick(this);
|
||||
// if (containerMenu != NULL && !containerMenu->stillValid(this)) {
|
||||
// closeContainer();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
int Player::getMaxHealth() {
|
||||
return MAX_HEALTH;
|
||||
}
|
||||
|
||||
//
|
||||
// Use items
|
||||
//
|
||||
bool Player::isUsingItem() {
|
||||
return !useItem.isNull();
|
||||
}
|
||||
|
||||
ItemInstance* Player::getUseItem() {
|
||||
return &useItem;
|
||||
}
|
||||
|
||||
void Player::spawnEatParticles(const ItemInstance* useItem, int count) {
|
||||
if (useItem->getUseAnimation() == UseAnim::drink) {
|
||||
level->playSound(this, "random.drink", 0.5f, level->random.nextFloat() * 0.1f + 0.9f);
|
||||
}
|
||||
else if (useItem->getUseAnimation() == UseAnim::eat) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
const float xx = -xRot * Mth::PI / 180;
|
||||
const float yy = -yRot * Mth::PI / 180;
|
||||
Vec3 d((random.nextFloat() - 0.5f) * 0.1f, Mth::random() * 0.1f + 0.1f, 0);
|
||||
d.xRot(xx);
|
||||
d.yRot(yy);
|
||||
Vec3 p((random.nextFloat() - 0.5f) * 0.3f, -random.nextFloat() * 0.6f - 0.3f, 0.6f);
|
||||
p.xRot(xx);
|
||||
p.yRot(yy);
|
||||
p = p.add(x, y + getHeadHeight(), z);
|
||||
level->addParticle(PARTICLETYPE(iconcrack), p.x, p.y, p.z, d.x, d.y + 0.05f, d.z, useItem->getItem()->id);
|
||||
}
|
||||
level->playSound(this, "random.eat", .5f + .5f * random.nextInt(2), (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::startUsingItem(ItemInstance instance, int duration) {
|
||||
if(instance == useItem) return;
|
||||
useItem = instance;
|
||||
useItemDuration = duration;
|
||||
if(!level->isClientSide) {
|
||||
setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::stopUsingItem() {
|
||||
if(getCarriedItem() != NULL && useItem.id == getCarriedItem()->id)
|
||||
getCarriedItem()->setAuxValue(useItem.getAuxValue());
|
||||
useItem.setNull();
|
||||
useItemDuration = 0;
|
||||
if(!level->isClientSide) {
|
||||
setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::releaseUsingItem() {
|
||||
if(!useItem.isNull()) {
|
||||
useItem.releaseUsing(level, this, useItemDuration);
|
||||
}
|
||||
stopUsingItem();
|
||||
}
|
||||
|
||||
void Player::completeUsingItem() {
|
||||
if(!useItem.isNull()) {
|
||||
spawnEatParticles(&useItem, 10);
|
||||
|
||||
// Check if the item is valid, and if we should overwrite the
|
||||
// inventory item afterwards.
|
||||
ItemInstance* selected = inventory->getSelected();
|
||||
bool doOverwrite = selected && ItemInstance::matches(&useItem, selected);
|
||||
|
||||
ItemInstance itemInstance = useItem.useTimeDepleted(level, this);
|
||||
|
||||
if (doOverwrite) {
|
||||
*selected = useItem;
|
||||
if (selected->count == 0)
|
||||
inventory->clearSlot(inventory->selected);
|
||||
}
|
||||
|
||||
/*
|
||||
int oldCount = useItem.count;
|
||||
if (!itemInstance.matches(&useItem)) {
|
||||
ItemInstance* selected = inventory->getSelected();
|
||||
if (ItemInstance::matches(&useItem, selected)) {
|
||||
if (selected) *selected = itemInstance;
|
||||
if (itemInstance.count == 0) {
|
||||
inventory->clearSlot(inventory->selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
stopUsingItem();
|
||||
}
|
||||
}
|
||||
|
||||
int Player::getUseItemDuration() {
|
||||
return useItemDuration;
|
||||
}
|
||||
|
||||
int Player::getTicksUsingItem() {
|
||||
if(isUsingItem()) {
|
||||
return useItem.getUseDuration() - useItemDuration;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Player::travel(float xa, float ya) {
|
||||
if (abilities.flying) {
|
||||
float ydo = yd;
|
||||
float ofs = flyingSpeed;
|
||||
flyingSpeed = 0.05f;
|
||||
super::travel(xa, ya);
|
||||
yd = ydo * 0.6f;
|
||||
flyingSpeed = ofs;
|
||||
} else {
|
||||
super::travel(xa, ya);
|
||||
}
|
||||
}
|
||||
|
||||
/*protected*/
|
||||
bool Player::isImmobile() {
|
||||
return health <= 0 || isSleeping();
|
||||
}
|
||||
|
||||
/*protected*/
|
||||
void Player::closeContainer() {
|
||||
containerMenu = NULL;
|
||||
//containerMenu = inventoryMenu;
|
||||
}
|
||||
|
||||
void Player::resetPos(bool clearMore) {
|
||||
if(!isSleeping()) {
|
||||
heightOffset = 1.62f;
|
||||
setSize(0.6f, 1.8f);
|
||||
super::resetPos(clearMore);
|
||||
}
|
||||
invisible = false;
|
||||
|
||||
if (clearMore) {
|
||||
health = getMaxHealth();
|
||||
deathTime = 0;
|
||||
playerIsSleeping = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*protected*/
|
||||
void Player::updateAi() {
|
||||
updateAttackAnim();
|
||||
}
|
||||
|
||||
int Player::getItemInHandIcon(ItemInstance* item, int layer) {
|
||||
int icon = item->getIcon();
|
||||
if(useItem.id != 0 && item->id == Item::bow->id) {
|
||||
int ticksHeld = (item->getUseDuration() - useItemDuration);
|
||||
if(ticksHeld >= BowItem::MAX_DRAW_DURATION - 2) {
|
||||
return 5 + 8 * 16;
|
||||
}
|
||||
if(ticksHeld > (2 * BowItem::MAX_DRAW_DURATION) / 3) {
|
||||
return 5 + 7*16;
|
||||
}
|
||||
if(ticksHeld > 0) {
|
||||
return 5 + 6 * 16;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
void Player::aiStep() {
|
||||
if (level->difficulty == Difficulty::PEACEFUL && health < MAX_HEALTH) {
|
||||
if (tickCount % (12 * SharedConstants::TicksPerSecond) == 0) heal(1);
|
||||
}
|
||||
//inventory.tick();
|
||||
oBob = bob;
|
||||
// moved the super::aiStep() part to the local player
|
||||
|
||||
float tBob = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
float tTilt = (float) Mth::atan(-yd * 0.2f) * 15.f;
|
||||
if (tBob > 0.1f) tBob = 0.1f;
|
||||
if (!onGround || health <= 0) tBob = 0;
|
||||
if (onGround || health <= 0) tTilt = 0;
|
||||
bob += (tBob - bob) * 0.4f;
|
||||
tilt += (tTilt - tilt) * 0.8f;
|
||||
|
||||
if (health > 0) {
|
||||
EntityList& entities = level->getEntities(this, bb.grow(1, 0, 1));
|
||||
for (unsigned int i = 0; i < entities.size(); i++) {
|
||||
Entity* e = entities[i];
|
||||
if (!e->removed) {
|
||||
touch(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*private*/
|
||||
void Player::touch(Entity* entity) {
|
||||
entity->playerTouch(this);
|
||||
}
|
||||
|
||||
int Player::getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
void Player::die(Entity* source) {
|
||||
super::die(source);
|
||||
this->setSize(0.2f, 0.2f);
|
||||
setPos(x, y, z);
|
||||
yd = 0.1f;
|
||||
|
||||
//inventory->dropAll(level->isClientSide);
|
||||
|
||||
if (source != NULL) {
|
||||
xd = -(float) Mth::cos((hurtDir + yRot) * Mth::PI / 180) * 0.1f;
|
||||
zd = -(float) Mth::sin((hurtDir + yRot) * Mth::PI / 180) * 0.1f;
|
||||
} else {
|
||||
xd = zd = 0;
|
||||
}
|
||||
this->heightOffset = 0.1f;
|
||||
}
|
||||
|
||||
void Player::reset() {
|
||||
super::reset();
|
||||
this->_init();
|
||||
}
|
||||
|
||||
void Player::_init() {
|
||||
oBob = bob = 0;
|
||||
swinging = 0;
|
||||
swingTime = 0;
|
||||
score = 0;
|
||||
}
|
||||
|
||||
float Player::getWalkingSpeedModifier() {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
|
||||
void Player::awardKillScore(Entity* victim, int score) {
|
||||
this->score += score;
|
||||
}
|
||||
|
||||
bool Player::isShootable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::isCreativeModeAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
//void Player::drop() {
|
||||
// //drop(inventory.removeItem(inventory.selected, 1), false);
|
||||
//}
|
||||
|
||||
void Player::drop(ItemInstance* item) {
|
||||
drop(item, false);
|
||||
}
|
||||
|
||||
void Player::drop(ItemInstance* item, bool randomly) {
|
||||
if (item == NULL || item->isNull())
|
||||
return;
|
||||
|
||||
ItemEntity* thrownItem = new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, *item);
|
||||
{ //@todo:itementity
|
||||
delete item;
|
||||
item = NULL;
|
||||
}
|
||||
thrownItem->throwTime = 20 * 2;
|
||||
|
||||
float pow = 0.1f;
|
||||
if (randomly) {
|
||||
float _pow = random.nextFloat() * 0.5f;
|
||||
float dir = random.nextFloat() * Mth::PI * 2;
|
||||
thrownItem->xd = -Mth::sin(dir) * _pow;
|
||||
thrownItem->zd = Mth::cos(dir) * _pow;
|
||||
thrownItem->yd = 0.2f;
|
||||
|
||||
} else {
|
||||
pow = 0.3f;
|
||||
thrownItem->xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow;
|
||||
thrownItem->zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow;
|
||||
thrownItem->yd = -Mth::sin(xRot / 180 * Mth::PI) * pow + 0.1f;
|
||||
pow = 0.02f;
|
||||
|
||||
float dir = random.nextFloat() * Mth::PI * 2;
|
||||
pow *= random.nextFloat();
|
||||
thrownItem->xd += Mth::cos(dir) * pow;
|
||||
thrownItem->yd += (random.nextFloat() - random.nextFloat()) * 0.1f;
|
||||
thrownItem->zd += Mth::sin(dir) * pow;
|
||||
}
|
||||
|
||||
reallyDrop(thrownItem);
|
||||
}
|
||||
|
||||
/*protected*/
|
||||
void Player::reallyDrop(ItemEntity* thrownItem) {
|
||||
level->addEntity(thrownItem);
|
||||
}
|
||||
|
||||
float Player::getDestroySpeed(Tile* tile) {
|
||||
float speed = inventory->getDestroySpeed(tile);
|
||||
//if (isUnderLiquid(Material.water)) speed /= 5;
|
||||
//if (!onGround) speed /= 5;
|
||||
return speed;
|
||||
}
|
||||
|
||||
bool Player::canDestroy(Tile* tile) {
|
||||
return inventory->canDestroy(tile);
|
||||
}
|
||||
|
||||
//@SuppressWarnings("unchecked")
|
||||
void Player::readAdditionalSaveData(CompoundTag* entityTag) {
|
||||
super::readAdditionalSaveData(entityTag);
|
||||
|
||||
if (entityTag->contains("Inventory", Tag::TAG_List)) {
|
||||
ListTag* inventoryList = entityTag->getList("Inventory");
|
||||
inventory->load(inventoryList);
|
||||
}
|
||||
if (entityTag->contains("Armor", Tag::TAG_List)) {
|
||||
loadArmor(armor, entityTag->getList("Armor"));
|
||||
}
|
||||
|
||||
dimension = entityTag->getInt("Dimension");
|
||||
|
||||
//return;
|
||||
if(entityTag->contains("Sleeping") && entityTag->contains("SleepTimer")
|
||||
&& entityTag->contains("BedPositionX") && entityTag->contains("BedPositionY") && entityTag->contains("BedPositionZ")) {
|
||||
playerIsSleeping = entityTag->getBoolean("Sleeping");
|
||||
sleepCounter = entityTag->getShort("SleepTimer");
|
||||
bedPosition = Pos(entityTag->getInt("BedPositionX"), entityTag->getInt("BedPositionY"), entityTag->getInt("BedPositionZ"));
|
||||
} else {
|
||||
playerIsSleeping = false;
|
||||
bedPosition = Pos(0,0,0);
|
||||
}
|
||||
|
||||
if(!playerIsSleeping) {
|
||||
stopSleepInBed(true, true, false);
|
||||
entityData.clearFlag<SharedFlagsInformation::SharedFlagsInformationType>(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG);
|
||||
} else {
|
||||
playerIsSleeping = false;
|
||||
startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z);
|
||||
entityData.setFlag<SharedFlagsInformation::SharedFlagsInformationType>(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG);
|
||||
}
|
||||
entityData.set<Pos>(DATA_BED_POSITION_ID, bedPosition);
|
||||
if (entityTag->contains("SpawnX") && entityTag->contains("SpawnY") && entityTag->contains("SpawnZ")) {
|
||||
respawnPosition.set(entityTag->getInt("SpawnX"), entityTag->getInt("SpawnY"), entityTag->getInt("SpawnZ"));
|
||||
}
|
||||
playerHasRespawnPosition = respawnPosition.y >= 0;
|
||||
}
|
||||
|
||||
void Player::addAdditonalSaveData(CompoundTag* entityTag) {
|
||||
super::addAdditonalSaveData(entityTag);
|
||||
|
||||
ListTag* inventoryTag = inventory->save(new ListTag());
|
||||
// if (inventoryTag->size() > 0)
|
||||
entityTag->put("Inventory", inventoryTag);
|
||||
//else
|
||||
// delete inventoryTag;
|
||||
|
||||
ListTag* armorTag = saveArmor(armor);
|
||||
entityTag->put("Armor", armorTag);
|
||||
|
||||
entityTag->putInt("Dimension", dimension);
|
||||
//return;
|
||||
|
||||
entityTag->putBoolean("Sleeping", isSleeping());
|
||||
entityTag->putShort("SleepTimer", sleepCounter);
|
||||
entityTag->putInt("BedPositionX", bedPosition.x);
|
||||
entityTag->putInt("BedPositionY", bedPosition.y);
|
||||
entityTag->putInt("BedPositionZ", bedPosition.z);
|
||||
|
||||
entityTag->putInt("SpawnX", respawnPosition.x);
|
||||
entityTag->putInt("SpawnY", respawnPosition.y);
|
||||
entityTag->putInt("SpawnZ", respawnPosition.z);
|
||||
}
|
||||
|
||||
//static Pos getRespawnPosition(Level level, CompoundTag entityTag) {
|
||||
// if (entityTag.contains("SpawnX") && entityTag.contains("SpawnY") && entityTag.contains("SpawnZ")) {
|
||||
// return /*new*/ Pos(entityTag.getInt("SpawnX"), entityTag.getInt("SpawnY"), entityTag.getInt("SpawnZ"));
|
||||
// }
|
||||
// return level.getSharedSpawnPos();
|
||||
//}
|
||||
|
||||
void Player::startCrafting(int x, int y, int z, int tableSize) {
|
||||
}
|
||||
|
||||
void Player::startStonecutting(int x, int y, int z) {
|
||||
}
|
||||
|
||||
void Player::openFurnace(FurnaceTileEntity* e) {
|
||||
}
|
||||
|
||||
void Player::take(Entity* e, int orgCount) {
|
||||
}
|
||||
|
||||
float Player::getHeadHeight() {
|
||||
return 0.12f; // heightOffset; // 0.12f;
|
||||
}
|
||||
|
||||
/*protected*/
|
||||
void Player::setDefaultHeadHeight() {
|
||||
heightOffset = 1.62f;
|
||||
}
|
||||
|
||||
bool Player::isHurt() {
|
||||
return health > 0 && health < getMaxHealth();
|
||||
}
|
||||
|
||||
bool Player::hurt(Entity* source, int dmg) {
|
||||
if (abilities.invulnerable) return false;
|
||||
|
||||
noActionTime = 0;
|
||||
if (health <= 0) return false;
|
||||
if(isSleeping() && !level->isClientSide) {
|
||||
stopSleepInBed(true, true, false);
|
||||
}
|
||||
|
||||
if (source != NULL && (source->getCreatureBaseType() == MobTypes::BaseEnemy
|
||||
|| source->getEntityTypeId() == EntityTypes::IdArrow)) {
|
||||
|
||||
if (source->isMob() && level->adventureSettings.noMvP)
|
||||
return false;
|
||||
|
||||
if (level->difficulty == Difficulty::PEACEFUL) dmg = 0;
|
||||
else if (level->difficulty == Difficulty::EASY) dmg = dmg / 3 + 1;
|
||||
else if (level->difficulty == Difficulty::HARD) dmg = dmg * 3 / 2;
|
||||
}
|
||||
|
||||
if (dmg == 0) return false;
|
||||
|
||||
// Entity* attacker = source;
|
||||
// //if (attacker instanceof Arrow) {
|
||||
// // if (((Arrow) attacker).owner != NULL) {
|
||||
// // attacker = ((Arrow) attacker).owner;
|
||||
// // }
|
||||
// //}
|
||||
return super::hurt(source, dmg);
|
||||
}
|
||||
|
||||
void Player::interact(Entity* entity) {
|
||||
if (entity->interact(this)) return;
|
||||
ItemInstance* item = inventory->getSelected();
|
||||
if (item != NULL && entity->isMob()) {
|
||||
item->interactEnemy((Mob*)entity);
|
||||
if (item->count <= 0) {
|
||||
//item.snap(this);
|
||||
inventory->clearSlot(inventory->selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Player::swing() {
|
||||
//LOGI("swinging: %d\n", swinging);
|
||||
// if (!swinging || swingTime >= 3 || swingTime < 0) {
|
||||
// swingTime = -1;
|
||||
// swinging = true;
|
||||
// }
|
||||
|
||||
//level->raknetInstance->send(owner, new AnimatePacket(AnimatePacket::Swing, this));
|
||||
//}
|
||||
//}
|
||||
|
||||
void Player::attack(Entity* entity) {
|
||||
int dmg = inventory->getAttackDamage(entity);
|
||||
if (dmg > 0) {
|
||||
entity->hurt(this, dmg);
|
||||
ItemInstance* item = inventory->getSelected();
|
||||
if (item != NULL && entity->isMob() && abilities.instabuild != true) {
|
||||
item->hurtEnemy((Mob*) entity);
|
||||
if (item->count <= 0) {
|
||||
//item->snap(this);
|
||||
inventory->clearSlot(inventory->selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::respawn() {
|
||||
}
|
||||
|
||||
/*protected static*/
|
||||
void Player::animateRespawn(Player* player, Level* level) {
|
||||
//for (int i = 0; i < 45; i++) {
|
||||
// float angle = i * Mth::PI * 4.0f / 25.0f;
|
||||
// float xo = Mth::cos(angle) * .7f;
|
||||
// float zo = Mth::sin(angle) * .7f;
|
||||
//}
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
void Player::animateRespawn() {}
|
||||
|
||||
//void carriedChanged(ItemInstance carried) {
|
||||
//}
|
||||
ItemInstance* Player::getCarriedItem() {
|
||||
return inventory->getSelected();
|
||||
}
|
||||
|
||||
void Player::remove() {
|
||||
invisible = true;
|
||||
super::remove();
|
||||
}
|
||||
|
||||
//@Override
|
||||
bool Player::isInWall() {
|
||||
return super::isInWall();
|
||||
}
|
||||
|
||||
bool Player::hasResource( int id ) {
|
||||
return inventory->hasResource(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is currently only relevant to client-side players. It will
|
||||
* try to load the messageId from the language file and display it to the
|
||||
* client.
|
||||
*/
|
||||
void Player::displayClientMessage(const std::string& messageId) {
|
||||
}
|
||||
|
||||
Pos Player::getRespawnPosition() {
|
||||
return respawnPosition;
|
||||
}
|
||||
|
||||
void Player::setRespawnPosition(const Pos& respawnPosition) { // @attn WARNING CHECK THIS THROUGH @fix @todo: rewrite
|
||||
if (respawnPosition.y < 0) {
|
||||
playerHasRespawnPosition = false;
|
||||
}
|
||||
else {
|
||||
playerHasRespawnPosition = true;
|
||||
}
|
||||
this->respawnPosition = respawnPosition;
|
||||
}
|
||||
|
||||
bool Player::isPlayer() { return true; }
|
||||
|
||||
/*static*/
|
||||
bool Player::isPlayer( Entity* e ) {
|
||||
return e && e->isPlayer();
|
||||
}
|
||||
|
||||
Player* Player::asPlayer( Entity* e ) {
|
||||
return isPlayer(e)? (Player*) e : NULL;
|
||||
}
|
||||
|
||||
void Player::openContainer(ChestTileEntity* container)
|
||||
{
|
||||
}
|
||||
|
||||
void Player::tileEntityDestroyed( int tileEntityId ) {
|
||||
|
||||
//LOGI("TileEntityDestroyed, container: %p, %p\n", this, containerMenu);
|
||||
|
||||
if (!containerMenu) return;
|
||||
|
||||
//LOGI("TileEntityDestroyed, id: %d, %p, %d\n", this, tileEntityId, ((FurnaceMenu*)containerMenu)->furnaceTileEntityId);
|
||||
|
||||
if (containerMenu->tileEntityDestroyedIsInvalid(tileEntityId))
|
||||
closeContainer();
|
||||
}
|
||||
|
||||
bool Player::canUseCarriedItemWhileMoving() {
|
||||
ItemInstance* item = getCarriedItem();
|
||||
return item &&
|
||||
( item->id == Item::bow->id
|
||||
|| item->getItem()->isFood());
|
||||
}
|
||||
|
||||
void Player::handleEntityEvent( char id ) {
|
||||
if (id == EntityEvent::USE_ITEM_COMPLETE) {
|
||||
completeUsingItem();
|
||||
} else {
|
||||
super::handleEntityEvent(id);
|
||||
}
|
||||
}
|
||||
|
||||
ItemInstance* Player::getSelectedItem() {
|
||||
return inventory->getSelected();
|
||||
}
|
||||
|
||||
bool Player::hasRespawnPosition(){
|
||||
return playerHasRespawnPosition;
|
||||
}
|
||||
|
||||
void Player::openTextEdit( TileEntity* tileEntity ) {
|
||||
// Do nothing on the server, this is a client thing :)
|
||||
}
|
||||
|
||||
//
|
||||
// Armor code. Move this out to an ArmorInventory
|
||||
//
|
||||
static ListTag* saveArmor(ItemInstance* armor) {
|
||||
ListTag* listTag = new ListTag();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CompoundTag* tag = new CompoundTag();
|
||||
armor[i].save(tag);
|
||||
listTag->add(tag);
|
||||
}
|
||||
return listTag;
|
||||
}
|
||||
|
||||
static void loadArmor(ItemInstance* armor, ListTag* listTag) {
|
||||
if (!listTag)
|
||||
return;
|
||||
|
||||
const int count = Mth::Min(4, listTag->size());
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Tag* tag = listTag->get(i);
|
||||
if (tag->getId() != Tag::TAG_Compound) continue;
|
||||
|
||||
armor[i].load((CompoundTag*) tag);
|
||||
}
|
||||
}
|
||||
|
||||
ItemInstance* Player::getArmor(int slot) {
|
||||
if (slot < 0 || slot >= NUM_ARMOR)
|
||||
return NULL;
|
||||
|
||||
if (armor[slot].isNull())
|
||||
return NULL;
|
||||
|
||||
return &armor[slot];
|
||||
}
|
||||
|
||||
void Player::setArmor(int slot, const ItemInstance* item) {
|
||||
if (item == NULL)
|
||||
armor[slot].setNull();
|
||||
else {
|
||||
armor[slot] = *item;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::hurtArmor( int dmg ) {
|
||||
dmg = Mth::Max(1, dmg / 4);
|
||||
|
||||
for (int i = 0; i < NUM_ARMOR; i++) {
|
||||
ItemInstance& item = armor[i];
|
||||
if (!ItemInstance::isArmorItem(&item))
|
||||
continue;
|
||||
|
||||
item.hurt(dmg);
|
||||
if (item.count == 0) {
|
||||
item.setNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Player::getArmorTypeHash() {
|
||||
return (armor[0].id ) +
|
||||
(armor[1].id << 8) +
|
||||
(armor[2].id << 16) +
|
||||
(armor[3].id << 24);
|
||||
}
|
||||
|
||||
int Player::getArmorValue() {
|
||||
int val = 0;
|
||||
|
||||
for (int i = 0; i < NUM_ARMOR; i++) {
|
||||
ItemInstance& item = armor[i];
|
||||
if (!ItemInstance::isArmorItem(&item))
|
||||
continue;
|
||||
|
||||
int baseProtection = ((ArmorItem*) item.getItem())->defense;
|
||||
val += baseProtection;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
201
src/world/entity/player/Player.h
Executable file
201
src/world/entity/player/Player.h
Executable file
@@ -0,0 +1,201 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PLAYER__Player_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PLAYER__Player_H__
|
||||
|
||||
//package net.minecraft.world.entity.player;
|
||||
|
||||
#include "Abilities.h"
|
||||
#include "../Mob.h"
|
||||
#include "../../Pos.h"
|
||||
#include "../../food/SimpleFoodData.h"
|
||||
#include "../../item/crafting/Recipe.h"
|
||||
|
||||
class Tile;
|
||||
class ItemEntity;
|
||||
class ItemInstance;
|
||||
class Inventory;
|
||||
class FillingContainer;
|
||||
class FurnaceTileEntity;
|
||||
class CompoundTag;
|
||||
class ChestTileEntity;
|
||||
class BaseContainerMenu;
|
||||
class TileEntity;
|
||||
class BedSleepingResult {
|
||||
public:
|
||||
static const int OK = 0;
|
||||
static const int NOT_POSSIBLE_HERE = 1;
|
||||
static const int NOT_POSSIBLE_NOW = 2;
|
||||
static const int TOO_FAR_AWAY = 3;
|
||||
static const int OTHER_PROBLEM = 4;
|
||||
static const int NOT_SAFE = 5;
|
||||
};
|
||||
|
||||
class Player: public Mob
|
||||
{
|
||||
typedef Mob super;
|
||||
typedef SynchedEntityData::TypeChar PlayerFlagIDType;
|
||||
|
||||
static const int DATA_PLAYER_FLAGS_ID = 16;
|
||||
static const int DATA_BED_POSITION_ID = 17;
|
||||
static const int PLAYER_SLEEP_FLAG = 1;
|
||||
|
||||
public:
|
||||
static const int MAX_NAME_LENGTH = 16;
|
||||
static const int MAX_HEALTH = 20;
|
||||
static const float DEFAULT_WALK_SPEED;
|
||||
static const float DEFAULT_FLY_SPEED;
|
||||
static const int SLEEP_DURATION = 100;
|
||||
static const int WAKE_UP_DURATION = 10;
|
||||
|
||||
Player(Level* level, bool isCreative);
|
||||
virtual ~Player();
|
||||
|
||||
void _init();
|
||||
virtual void reset();
|
||||
|
||||
static bool isPlayer(Entity* e);
|
||||
static Player* asPlayer(Entity* e);
|
||||
|
||||
virtual void tick();
|
||||
void aiStep();
|
||||
void travel(float xa, float ya);
|
||||
|
||||
virtual float getWalkingSpeedModifier();
|
||||
|
||||
void die(Entity* source);
|
||||
void remove();
|
||||
void respawn();
|
||||
void resetPos(bool clearMore);
|
||||
Pos getRespawnPosition();
|
||||
void setRespawnPosition(const Pos& respawnPosition);
|
||||
|
||||
bool isShootable();
|
||||
bool isCreativeModeAllowed();
|
||||
bool isPlayer();
|
||||
bool isInWall();
|
||||
|
||||
virtual bool hasResource( int id );
|
||||
|
||||
bool isUsingItem();
|
||||
ItemInstance* getUseItem();
|
||||
|
||||
void startUsingItem(ItemInstance instance, int duration);
|
||||
void stopUsingItem();
|
||||
void releaseUsingItem();
|
||||
virtual void completeUsingItem();
|
||||
|
||||
int getUseItemDuration();
|
||||
int getTicksUsingItem();
|
||||
|
||||
int getScore();
|
||||
void awardKillScore(Entity* victim, int score);
|
||||
void handleEntityEvent(char id);
|
||||
|
||||
virtual void take(Entity* e, int orgCount);
|
||||
//void drop();
|
||||
virtual void drop(ItemInstance* item);
|
||||
virtual void drop(ItemInstance* item, bool randomly);
|
||||
void reallyDrop(ItemEntity* thrownItem);
|
||||
|
||||
bool canDestroy(Tile* tile);
|
||||
float getDestroySpeed(Tile* tile);
|
||||
|
||||
int getMaxHealth();
|
||||
bool isHurt();
|
||||
|
||||
bool hurt(Entity* source, int dmg);
|
||||
void hurtArmor(int dmg);
|
||||
void setArmor(int slot, const ItemInstance* item);
|
||||
ItemInstance* getArmor(int slot);
|
||||
int getArmorTypeHash();
|
||||
|
||||
void interact(Entity* entity);
|
||||
void attack(Entity* entity);
|
||||
virtual ItemInstance* getCarriedItem();
|
||||
bool canUseCarriedItemWhileMoving();
|
||||
|
||||
virtual void startCrafting(int x, int y, int z, int tableSize);
|
||||
virtual void startStonecutting(int x, int y, int z);
|
||||
|
||||
virtual void openContainer(ChestTileEntity* container);
|
||||
virtual void openFurnace(FurnaceTileEntity* e);
|
||||
void tileEntityDestroyed( int tileEntityId );
|
||||
|
||||
virtual void displayClientMessage(const std::string& messageId);
|
||||
virtual void animateRespawn();
|
||||
float getHeadHeight();
|
||||
|
||||
// id == 0 -> not possible to create via serialization (yet)
|
||||
int getEntityTypeId() const { return 0; }
|
||||
|
||||
int getItemInHandIcon(ItemInstance* item, int layer);
|
||||
bool isSleeping();
|
||||
virtual int startSleepInBed(int x, int y, int z);
|
||||
virtual void stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint);
|
||||
virtual int getSleepTimer();
|
||||
void setAllPlayersSleeping();
|
||||
float getSleepRotation();
|
||||
bool isSleepingLongEnough();
|
||||
ItemInstance* getSelectedItem();
|
||||
Inventory* inventory;
|
||||
bool hasRespawnPosition();
|
||||
virtual void openTextEdit( TileEntity* tileEntity );
|
||||
//AbstractContainerMenu inventoryMenu;
|
||||
//AbstractContainerMenu containerMenu;
|
||||
int getArmorValue();
|
||||
protected:
|
||||
bool isImmobile();
|
||||
void updateAi();
|
||||
virtual void closeContainer();
|
||||
void setDefaultHeadHeight();
|
||||
|
||||
void readAdditionalSaveData(CompoundTag* entityTag);
|
||||
void addAdditonalSaveData(CompoundTag* entityTag);
|
||||
|
||||
void setBedOffset(int bedDirection);
|
||||
bool checkBed();
|
||||
|
||||
static void animateRespawn(Player* player, Level* level);
|
||||
void spawnEatParticles(const ItemInstance* useItem, int count);
|
||||
private:
|
||||
void touch(Entity* entity);
|
||||
|
||||
//void eat( ItemInstance* instance );
|
||||
|
||||
public:
|
||||
char userType;
|
||||
int score;
|
||||
float oBob, bob;
|
||||
|
||||
std::string name;
|
||||
int dimension;
|
||||
|
||||
Abilities abilities;
|
||||
SimpleFoodData foodData;
|
||||
//Stats stats;
|
||||
|
||||
BaseContainerMenu* containerMenu;
|
||||
|
||||
// ok I know it's not so nice to build in RakNet dependency here, BUT I DON'T CARE! MUAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHHAHAHAHAHAHAHAHAHHAHAHAHAHAHAHA
|
||||
RakNet::RakNetGUID owner;
|
||||
bool hasFakeInventory;
|
||||
Pos bedPosition;
|
||||
float bedOffsetX;
|
||||
float bedOffsetY;
|
||||
float bedOffsetZ;
|
||||
protected:
|
||||
ItemInstance useItem;
|
||||
int useItemDuration;
|
||||
short sleepCounter;
|
||||
|
||||
static const int NUM_ARMOR = 4;
|
||||
private:
|
||||
Pos respawnPosition;
|
||||
bool playerHasRespawnPosition;
|
||||
bool playerIsSleeping;
|
||||
bool allPlayersSleeping;
|
||||
|
||||
ItemInstance armor[NUM_ARMOR];
|
||||
//FishingHook fishing = NULL;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PLAYER__Player_H__*/
|
||||
346
src/world/entity/projectile/Arrow.cpp
Executable file
346
src/world/entity/projectile/Arrow.cpp
Executable file
@@ -0,0 +1,346 @@
|
||||
#include "Arrow.h"
|
||||
#include "../Mob.h"
|
||||
#include "../player/Player.h"
|
||||
#include "../../item/Item.h"
|
||||
#include "../../item/ItemInstance.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../level/tile/Tile.h"
|
||||
#include "../../../util/Mth.h"
|
||||
|
||||
#include "../../../nbt/CompoundTag.h"
|
||||
|
||||
const float Arrow::ARROW_BASE_DAMAGE = 2.0f;
|
||||
|
||||
Arrow::Arrow( Level* level )
|
||||
: super(level),
|
||||
playerArrow(false),
|
||||
ownerId(0)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
Arrow::Arrow( Level* level, float x, float y, float z )
|
||||
: super(level),
|
||||
playerArrow(false),
|
||||
ownerId(0)
|
||||
{
|
||||
_init();
|
||||
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
}
|
||||
|
||||
Arrow::Arrow( Level* level, Mob* mob, float power )
|
||||
: super(level),
|
||||
ownerId(mob->entityId),
|
||||
playerArrow(mob->isPlayer())
|
||||
{
|
||||
_init();
|
||||
|
||||
moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
|
||||
|
||||
const float dx = Mth::cos(yRot * Mth::DEGRAD);
|
||||
const float dz = Mth::sin(yRot * Mth::DEGRAD);
|
||||
x -= dx * 0.16f;
|
||||
y -= 0.1f;
|
||||
z -= dz * 0.16f;
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
|
||||
const float dxx = Mth::cos(xRot / 180 * Mth::PI);
|
||||
xd = -dz * dxx;
|
||||
zd = dx * dxx;
|
||||
yd = -Mth::sin(xRot / 180 * Mth::PI);
|
||||
|
||||
shoot(xd, yd, zd, power * 1.5f, 1);
|
||||
}
|
||||
|
||||
void Arrow::_init()
|
||||
{
|
||||
entityRendererId = ER_ARROW_RENDERER;
|
||||
setSize(0.5f, 0.5f);
|
||||
|
||||
shakeTime = 0;
|
||||
critArrow = false;
|
||||
|
||||
xTile = -1;
|
||||
yTile = -1;
|
||||
zTile = -1;
|
||||
lastTile = 0;
|
||||
lastData = 0;
|
||||
inGround = false;
|
||||
life = 0;
|
||||
flightTime = 0;
|
||||
}
|
||||
|
||||
void Arrow::shoot( float xd, float yd, float zd, float pow, float uncertainty )
|
||||
{
|
||||
float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd);
|
||||
|
||||
xd /= dist;
|
||||
yd /= dist;
|
||||
zd /= dist;
|
||||
|
||||
const float radius = 0.0075f * uncertainty;
|
||||
xd += sharedRandom.nextGaussian() * radius;
|
||||
yd += sharedRandom.nextGaussian() * radius;
|
||||
zd += sharedRandom.nextGaussian() * radius;
|
||||
|
||||
xd *= pow;
|
||||
yd *= pow;
|
||||
zd *= pow;
|
||||
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
|
||||
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
|
||||
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
|
||||
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
|
||||
life = 0;
|
||||
}
|
||||
|
||||
void Arrow::lerpMotion( float xd, float yd, float zd )
|
||||
{
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
if (xRotO == 0 && yRotO == 0) {
|
||||
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
|
||||
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
|
||||
moveTo(x, y, z, yRot, xRot);
|
||||
life = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Arrow::tick()
|
||||
{
|
||||
super::tick();
|
||||
|
||||
if (xRotO == 0 && yRotO == 0) {
|
||||
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG);
|
||||
xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int t = level->getTile(xTile, yTile, zTile);
|
||||
if (t > 0) {
|
||||
Tile::tiles[t]->updateShape(level, xTile, yTile, zTile);
|
||||
AABB* aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile);
|
||||
if (aabb != NULL && aabb->contains(Vec3(x, y, z))) {
|
||||
inGround = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shakeTime > 0) shakeTime--;
|
||||
|
||||
if (inGround) {
|
||||
// xd = 0;
|
||||
// yd = 0;
|
||||
// zd = 0;
|
||||
int tile = level->getTile(xTile, yTile, zTile);
|
||||
int data = level->getData(xTile, yTile, zTile);
|
||||
if (tile != lastTile || data != lastData) {
|
||||
inGround = false;
|
||||
|
||||
xd *= sharedRandom.nextFloat() * 0.2f;
|
||||
yd *= sharedRandom.nextFloat() * 0.2f;
|
||||
zd *= sharedRandom.nextFloat() * 0.2f;
|
||||
life = 0;
|
||||
flightTime = 0;
|
||||
return;
|
||||
} else {
|
||||
if (++life == 60 * SharedConstants::TicksPerSecond) remove();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
flightTime++;
|
||||
}
|
||||
|
||||
Vec3 from(x, y, z);
|
||||
Vec3 to(x + xd, y + yd, z + zd);
|
||||
HitResult res = level->clip(from, to, false, true);
|
||||
|
||||
from.set(x, y, z);
|
||||
to.set(x + xd, y + yd, z + zd);
|
||||
if (res.isHit()) {
|
||||
to.set(res.pos.x, res.pos.y, res.pos.z);
|
||||
}
|
||||
Entity* hitEntity = NULL;
|
||||
EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1));
|
||||
float nearest = 0;
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
Entity* e = objects[i];
|
||||
if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue;
|
||||
|
||||
float rr = 0.3f;
|
||||
AABB bb = e->bb.grow(rr, rr, rr);
|
||||
HitResult p = bb.clip(from, to);
|
||||
if (p.isHit()) {
|
||||
float dd = from.distanceTo(p.pos);
|
||||
if (dd < nearest || nearest == 0) {
|
||||
hitEntity = e;
|
||||
nearest = dd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hitEntity != NULL) {
|
||||
res = HitResult(hitEntity);
|
||||
}
|
||||
|
||||
if (res.isHit()) {
|
||||
if (res.type == ENTITY) {
|
||||
float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd);
|
||||
int dmg = (int) std::ceil(pow * ARROW_BASE_DAMAGE);
|
||||
|
||||
if (critArrow) dmg += sharedRandom.nextInt(dmg / 2 + 2);
|
||||
|
||||
//@todo
|
||||
//DamageSource damageSource = NULL;
|
||||
//if (owner == NULL) {
|
||||
// damageSource = DamageSource.arrow(this, this);
|
||||
//} else {
|
||||
// damageSource = DamageSource.arrow(this, owner);
|
||||
//}
|
||||
|
||||
//if (res.entity->hurt(damageSource, dmg)) {
|
||||
// if (res.entity instanceof Mob) {
|
||||
|
||||
if (res.entity->hurt(this, dmg)) {
|
||||
if (res.entity->isMob()) {
|
||||
((Mob*) res.entity)->arrowCount++;
|
||||
}
|
||||
level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f));
|
||||
remove();
|
||||
} else {
|
||||
xd *= -0.1f;
|
||||
yd *= -0.1f;
|
||||
zd *= -0.1f;
|
||||
yRot += 180;
|
||||
yRotO += 180;
|
||||
flightTime = 0;
|
||||
}
|
||||
} else {
|
||||
xTile = res.x;
|
||||
yTile = res.y;
|
||||
zTile = res.z;
|
||||
lastTile = level->getTile(xTile, yTile, zTile);
|
||||
lastData = level->getData(xTile, yTile, zTile);
|
||||
xd = (float) (res.pos.x - x);
|
||||
yd = (float) (res.pos.y - y);
|
||||
zd = (float) (res.pos.z - z);
|
||||
float dd = Mth::sqrt(xd * xd + yd * yd + zd * zd);
|
||||
x -= (xd / dd) * 0.05f;
|
||||
y -= (yd / dd) * 0.05f;
|
||||
z -= (zd / dd) * 0.05f;
|
||||
|
||||
level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f));
|
||||
inGround = true;
|
||||
shakeTime = 7;
|
||||
critArrow = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (critArrow) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
level->addParticle(PARTICLETYPE(crit), x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2f, -zd);
|
||||
}
|
||||
}
|
||||
|
||||
x += xd;
|
||||
y += yd;
|
||||
z += zd;
|
||||
|
||||
float sd = Mth::sqrt(xd * xd + zd * zd);
|
||||
yRot = std::atan2(xd, zd) * Mth::RADDEG;
|
||||
xRot = std::atan2(yd, sd) * Mth::RADDEG;
|
||||
|
||||
while (xRot - xRotO < -180)
|
||||
xRotO -= 360;
|
||||
while (xRot - xRotO >= 180)
|
||||
xRotO += 360;
|
||||
|
||||
while (yRot - yRotO < -180)
|
||||
yRotO -= 360;
|
||||
while (yRot - yRotO >= 180)
|
||||
yRotO += 360;
|
||||
|
||||
xRot = xRotO + (xRot - xRotO) * 0.2f;
|
||||
yRot = yRotO + (yRot - yRotO) * 0.2f;
|
||||
|
||||
|
||||
float inertia = 0.99f;
|
||||
float gravity = 0.05f;
|
||||
|
||||
if (isInWater()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float s = 1 / 4.0f;
|
||||
level->addParticle(PARTICLETYPE(bubble), x - xd * s, y - yd * s, z - zd * s, xd, yd, zd);
|
||||
}
|
||||
inertia = 0.80f;
|
||||
}
|
||||
|
||||
xd *= inertia;
|
||||
yd *= inertia;
|
||||
zd *= inertia;
|
||||
yd -= gravity;
|
||||
|
||||
setPos(x, y, z);
|
||||
}
|
||||
|
||||
void Arrow::addAdditonalSaveData( CompoundTag* tag )
|
||||
{
|
||||
tag->putShort("xTile", (short) xTile);
|
||||
tag->putShort("yTile", (short) yTile);
|
||||
tag->putShort("zTile", (short) zTile);
|
||||
tag->putByte("inTile", (char) lastTile);
|
||||
tag->putByte("inData", (char) lastData);
|
||||
tag->putByte("shake", (char) shakeTime);
|
||||
tag->putByte("inGround", (char) (inGround ? 1 : 0));
|
||||
tag->putBoolean("player", playerArrow);
|
||||
}
|
||||
|
||||
void Arrow::readAdditionalSaveData( CompoundTag* tag )
|
||||
{
|
||||
xTile = tag->getShort("xTile");
|
||||
yTile = tag->getShort("yTile");
|
||||
zTile = tag->getShort("zTile");
|
||||
lastTile = tag->getByte("inTile") & 0xff;
|
||||
lastData = tag->getByte("inData") & 0xff;
|
||||
shakeTime = tag->getByte("shake") & 0xff;
|
||||
inGround = tag->getByte("inGround") == 1;
|
||||
playerArrow = tag->getBoolean("player");
|
||||
}
|
||||
|
||||
void Arrow::playerTouch( Player* player )
|
||||
{
|
||||
if (level->isClientSide) return;
|
||||
|
||||
if (inGround && playerArrow && shakeTime <= 0) {
|
||||
ItemInstance item(Item::arrow, 1);
|
||||
if (player->inventory->add(&item)) {
|
||||
level->playSound(this, "random.pop", 0.2f, ((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f + 1.0f) * 2.f);
|
||||
player->take(this, 1);
|
||||
remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Arrow::getShadowHeightOffs() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Arrow::getEntityTypeId() const {
|
||||
return EntityTypes::IdArrow;
|
||||
}
|
||||
|
||||
int Arrow::getAuxData() {
|
||||
return ownerId;
|
||||
}
|
||||
57
src/world/entity/projectile/Arrow.h
Executable file
57
src/world/entity/projectile/Arrow.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__
|
||||
|
||||
//package net.minecraft.world.entity.projectile;
|
||||
|
||||
#include "../Entity.h"
|
||||
|
||||
class Level;
|
||||
class Mob;
|
||||
class CompoundTag;
|
||||
|
||||
class Arrow: public Entity
|
||||
{
|
||||
typedef Entity super;
|
||||
// base damage, multiplied with velocity
|
||||
static const float ARROW_BASE_DAMAGE;
|
||||
|
||||
public:
|
||||
Arrow(Level* level);
|
||||
Arrow(Level* level, float x, float y, float z);
|
||||
Arrow(Level* level, Mob* mob, float power);
|
||||
|
||||
void _init();
|
||||
|
||||
void shoot(float xd, float yd, float zd, float pow, float uncertainty);
|
||||
|
||||
void lerpMotion(float xd, float yd, float zd);
|
||||
|
||||
void tick();
|
||||
|
||||
int getEntityTypeId() const;
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
void playerTouch(Player* player);
|
||||
|
||||
float getShadowHeightOffs();
|
||||
|
||||
int getAuxData();
|
||||
public:
|
||||
bool playerArrow;
|
||||
int shakeTime;
|
||||
int ownerId;
|
||||
bool critArrow;
|
||||
private:
|
||||
int xTile;
|
||||
int yTile;
|
||||
int zTile;
|
||||
int lastTile;
|
||||
int lastData;
|
||||
bool inGround;
|
||||
int life;
|
||||
int flightTime;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Arrow_H__*/
|
||||
50
src/world/entity/projectile/Snowball.h
Executable file
50
src/world/entity/projectile/Snowball.h
Executable file
@@ -0,0 +1,50 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__
|
||||
|
||||
//package net.minecraft.world.entity->projectile;
|
||||
|
||||
#include "Throwable.h"
|
||||
#include "../Mob.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../phys/HitResult.h"
|
||||
|
||||
class Snowball: public Throwable
|
||||
{
|
||||
typedef Throwable super;
|
||||
public:
|
||||
Snowball(Level* level)
|
||||
: super(level)
|
||||
{
|
||||
entityRendererId = ER_SNOWBALL_RENDERER;
|
||||
}
|
||||
|
||||
Snowball(Level* level, Mob* mob)
|
||||
: super(level, mob)
|
||||
{
|
||||
entityRendererId = ER_SNOWBALL_RENDERER;
|
||||
}
|
||||
|
||||
Snowball(Level* level, float x, float y, float z)
|
||||
: super(level, x, y, z)
|
||||
{
|
||||
entityRendererId = ER_SNOWBALL_RENDERER;
|
||||
}
|
||||
|
||||
virtual int getEntityTypeId() const {
|
||||
return EntityTypes::IdSnowball;
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
void onHit(const HitResult& res) {
|
||||
if (res.type == ENTITY)
|
||||
res.entity->hurt(this, 0);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
level->addParticle(PARTICLETYPE(snowballpoof), x, y, z, 0, 0, 0);
|
||||
|
||||
if (!level->isClientSide)
|
||||
remove();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Snowball_H__*/
|
||||
260
src/world/entity/projectile/Throwable.cpp
Executable file
260
src/world/entity/projectile/Throwable.cpp
Executable file
@@ -0,0 +1,260 @@
|
||||
#include "Throwable.h"
|
||||
#include "../player/Player.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../../util/Mth.h"
|
||||
#include "../../phys/HitResult.h"
|
||||
|
||||
Throwable::Throwable( Level* level )
|
||||
: super(level)
|
||||
{
|
||||
_init();
|
||||
setSize(0.25f, 0.25f);
|
||||
}
|
||||
|
||||
Throwable::Throwable( Level* level, Mob* mob )
|
||||
: super(level)
|
||||
{
|
||||
_init();
|
||||
setSize(0.25f, 0.25f);
|
||||
|
||||
ownerId = mob->entityId;
|
||||
|
||||
this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
|
||||
|
||||
const float rcos = Mth::cos(yRot / 180 * Mth::PI);
|
||||
const float rsin = Mth::sin(yRot / 180 * Mth::PI);
|
||||
x -= rcos * 0.16f;
|
||||
y -= 0.1f;
|
||||
z -= rsin * 0.16f;
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
|
||||
if (mob->isPlayer()) {
|
||||
shoot(mob->aimDirection, getThrowPower(), 1);
|
||||
} else {
|
||||
float xd = (-rsin * Mth::cos(xRot / 180 * Mth::PI));
|
||||
float zd = ( rcos * Mth::cos(xRot / 180 * Mth::PI));
|
||||
float yd = (-Mth::sin((xRot + getThrowUpAngleOffset()) / 180 * Mth::PI));
|
||||
shoot(xd, yd, zd, getThrowPower(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
Throwable::Throwable( Level* level, float x, float y, float z )
|
||||
: super(level)
|
||||
{
|
||||
_init();
|
||||
setSize(0.25f, 0.25f);
|
||||
|
||||
this->setPos(x, y, z);
|
||||
this->heightOffset = 0;
|
||||
}
|
||||
|
||||
void Throwable::_init() {
|
||||
ownerId = 0;
|
||||
shakeTime = 0;
|
||||
inGround = false;
|
||||
|
||||
life = 0;
|
||||
flightTime = 0;
|
||||
xTile = -1;
|
||||
yTile = -1;
|
||||
zTile = -1;
|
||||
lastTile = 0;
|
||||
}
|
||||
|
||||
bool Throwable::shouldRenderAtSqrDistance( float distance ) {
|
||||
float size = bb.getSize() * 4;
|
||||
size *= 64.0f;
|
||||
return distance < size * size;
|
||||
}
|
||||
|
||||
float Throwable::getThrowPower() {
|
||||
return 1.5f;
|
||||
}
|
||||
|
||||
float Throwable::getThrowUpAngleOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Throwable::getGravity() {
|
||||
return 0.03f;
|
||||
}
|
||||
|
||||
void Throwable::shoot(const Vec3& v, float pow, float uncertainty) {
|
||||
shoot(v.x, v.y, v.z, pow, uncertainty);
|
||||
}
|
||||
|
||||
void Throwable::shoot( float xd, float yd, float zd, float pow, float uncertainty ) {
|
||||
float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd);
|
||||
|
||||
if (dist >= 0.001f) {
|
||||
xd /= dist;
|
||||
yd /= dist;
|
||||
zd /= dist;
|
||||
} else {
|
||||
xd = yd = zd = 0;
|
||||
}
|
||||
|
||||
xd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
|
||||
yd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
|
||||
zd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty;
|
||||
|
||||
xd *= pow;
|
||||
yd *= pow;
|
||||
zd *= pow;
|
||||
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
|
||||
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
|
||||
yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI);
|
||||
xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI);
|
||||
life = 0;
|
||||
}
|
||||
|
||||
void Throwable::lerpMotion( float xd, float yd, float zd ) {
|
||||
this->xd = xd;
|
||||
this->yd = yd;
|
||||
this->zd = zd;
|
||||
if (xRotO == 0 && yRotO == 0) {
|
||||
float sd = (float) Mth::sqrt(xd * xd + zd * zd);
|
||||
yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI);
|
||||
xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI);
|
||||
}
|
||||
}
|
||||
|
||||
void Throwable::tick() {
|
||||
xOld = x;
|
||||
yOld = y;
|
||||
zOld = z;
|
||||
super::tick();
|
||||
|
||||
if (shakeTime > 0) shakeTime--;
|
||||
|
||||
if (inGround) {
|
||||
// xd = 0;
|
||||
// yd = 0;
|
||||
// zd = 0;
|
||||
int tile = level->getTile(xTile, yTile, zTile);
|
||||
if (tile != lastTile) {
|
||||
inGround = false;
|
||||
|
||||
xd *= sharedRandom.nextFloat() * 0.2f;
|
||||
yd *= sharedRandom.nextFloat() * 0.2f;
|
||||
zd *= sharedRandom.nextFloat() * 0.2f;
|
||||
life = 0;
|
||||
flightTime = 0;
|
||||
} else {
|
||||
life++;
|
||||
if (life == 20 * 60)
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
flightTime++;
|
||||
}
|
||||
|
||||
Vec3 from(x, y, z);
|
||||
Vec3 to(x + xd, y + yd, z + zd);
|
||||
HitResult res = level->clip(from, to);
|
||||
|
||||
from.set(x, y, z);
|
||||
to.set(x + xd, y + yd, z + zd);
|
||||
if (res.isHit())
|
||||
to.set(res.pos.x, res.pos.y, res.pos.z);
|
||||
|
||||
if (!level->isClientSide) {
|
||||
Entity* hitEntity = NULL;
|
||||
EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1));
|
||||
float nearest = 0;
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
Entity* e = objects[i];
|
||||
if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue;
|
||||
|
||||
float rr = 0.3f;
|
||||
AABB bb = e->bb.grow(rr, rr, rr);
|
||||
HitResult p = bb.clip(from, to);
|
||||
if (p.isHit()) {
|
||||
float dd = from.distanceTo(p.pos);
|
||||
if (dd < nearest || nearest == 0) {
|
||||
hitEntity = e;
|
||||
nearest = dd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hitEntity != NULL)
|
||||
res = HitResult(hitEntity);
|
||||
}
|
||||
|
||||
if (res.isHit())
|
||||
onHit(res);
|
||||
|
||||
x += xd;
|
||||
y += yd;
|
||||
z += zd;
|
||||
|
||||
float sd = Mth::sqrt(xd * xd + zd * zd);
|
||||
yRot = Mth::atan2(xd, zd) * 180 / Mth::PI;
|
||||
xRot = Mth::atan2(yd, sd) * 180 / Mth::PI;
|
||||
|
||||
while (xRot - xRotO < -180)
|
||||
xRotO -= 360;
|
||||
while (xRot - xRotO >= 180)
|
||||
xRotO += 360;
|
||||
|
||||
while (yRot - yRotO < -180)
|
||||
yRotO -= 360;
|
||||
while (yRot - yRotO >= 180)
|
||||
yRotO += 360;
|
||||
|
||||
xRot = xRotO + (xRot - xRotO) * 0.2f;
|
||||
yRot = yRotO + (yRot - yRotO) * 0.2f;
|
||||
|
||||
|
||||
float inertia = 0.99f;
|
||||
float gravity = getGravity();
|
||||
|
||||
if (isInWater()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float s = 1 / 4.0f;
|
||||
level->addParticle("bubble", x - xd * s, y - yd * s, z - zd * s, xd, yd, zd);
|
||||
}
|
||||
inertia = 0.80f;
|
||||
}
|
||||
|
||||
xd *= inertia;
|
||||
yd *= inertia;
|
||||
zd *= inertia;
|
||||
yd -= gravity;
|
||||
|
||||
setPos(x, y, z);
|
||||
}
|
||||
|
||||
float Throwable::getShadowHeightOffs() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Throwable::addAdditonalSaveData( CompoundTag* tag ) {
|
||||
tag->putShort("xTile", (short) xTile);
|
||||
tag->putShort("yTile", (short) yTile);
|
||||
tag->putShort("zTile", (short) zTile);
|
||||
tag->putByte("inTile", (char) lastTile);
|
||||
tag->putByte("shake", (char) shakeTime);
|
||||
tag->putByte("inGround", (char) (inGround ? 1 : 0));
|
||||
}
|
||||
|
||||
void Throwable::readAdditionalSaveData( CompoundTag* tag ) {
|
||||
xTile = tag->getShort("xTile");
|
||||
yTile = tag->getShort("yTile");
|
||||
zTile = tag->getShort("zTile");
|
||||
lastTile = tag->getByte("inTile") & 0xff;
|
||||
shakeTime = tag->getByte("shake") & 0xff;
|
||||
inGround = tag->getByte("inGround") == 1;
|
||||
}
|
||||
|
||||
int Throwable::getAuxData() {
|
||||
return ownerId;
|
||||
}
|
||||
63
src/world/entity/projectile/Throwable.h
Executable file
63
src/world/entity/projectile/Throwable.h
Executable file
@@ -0,0 +1,63 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__
|
||||
|
||||
//package net.minecraft.world.entity->projectile;
|
||||
|
||||
class Level;
|
||||
class Mob;
|
||||
class Player;
|
||||
class CompoundTag;
|
||||
|
||||
#include "../Entity.h"
|
||||
|
||||
class HitResult;
|
||||
|
||||
/*abstract*/
|
||||
class Throwable: public Entity
|
||||
{
|
||||
typedef Entity super;
|
||||
public:
|
||||
Throwable(Level* level);
|
||||
Throwable(Level* level, Mob* mob);
|
||||
Throwable(Level* level, float x, float y, float z);
|
||||
|
||||
void shoot(const Vec3& v, float pow, float uncertainty);
|
||||
void shoot(float xd, float yd, float zd, float pow, float uncertainty);
|
||||
|
||||
void tick();
|
||||
void lerpMotion(float xd, float yd, float zd);
|
||||
|
||||
void addAdditonalSaveData(CompoundTag* tag);
|
||||
void readAdditionalSaveData(CompoundTag* tag);
|
||||
|
||||
bool shouldRenderAtSqrDistance(float distance);
|
||||
|
||||
float getShadowHeightOffs();
|
||||
|
||||
int getAuxData();
|
||||
protected:
|
||||
virtual float getThrowPower();
|
||||
virtual float getThrowUpAngleOffset();
|
||||
|
||||
virtual float getGravity();
|
||||
|
||||
virtual void onHit(const HitResult& res) = 0;
|
||||
|
||||
private:
|
||||
void _init();
|
||||
|
||||
public:
|
||||
int shakeTime;
|
||||
protected:
|
||||
bool inGround;
|
||||
int ownerId;
|
||||
private:
|
||||
int life;
|
||||
int flightTime;
|
||||
int xTile;
|
||||
int yTile;
|
||||
int zTile;
|
||||
int lastTile;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__Throwable_H__*/
|
||||
63
src/world/entity/projectile/ThrownEgg.h
Executable file
63
src/world/entity/projectile/ThrownEgg.h
Executable file
@@ -0,0 +1,63 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__
|
||||
#define NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__
|
||||
|
||||
//package net.minecraft.world.entity->projectile;
|
||||
|
||||
#include "Throwable.h"
|
||||
#include "../Mob.h"
|
||||
#include "../animal/Chicken.h"
|
||||
#include "../../level/Level.h"
|
||||
#include "../../phys/HitResult.h"
|
||||
|
||||
class ThrownEgg: public Throwable
|
||||
{
|
||||
typedef Throwable super;
|
||||
public:
|
||||
ThrownEgg(Level* level)
|
||||
: super(level)
|
||||
{
|
||||
entityRendererId = ER_THROWNEGG_RENDERER;
|
||||
}
|
||||
|
||||
ThrownEgg(Level* level, Mob* mob)
|
||||
: super(level, mob)
|
||||
{
|
||||
entityRendererId = ER_THROWNEGG_RENDERER;
|
||||
}
|
||||
|
||||
ThrownEgg(Level* level, float x, float y, float z)
|
||||
: super(level, x, y, z)
|
||||
{
|
||||
entityRendererId = ER_THROWNEGG_RENDERER;
|
||||
}
|
||||
|
||||
virtual int getEntityTypeId() const {
|
||||
return EntityTypes::IdThrownEgg;
|
||||
}
|
||||
|
||||
/*@Override*/
|
||||
protected:
|
||||
void onHit(const HitResult& res) {
|
||||
if (res.type == ENTITY)
|
||||
res.entity->hurt(this, 0);
|
||||
|
||||
if (!level->isClientSide && sharedRandom.nextInt(8) == 0) {
|
||||
int count = 1;
|
||||
if (sharedRandom.nextInt(32) == 0) count = 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Chicken* chicken = new Chicken(level);
|
||||
//chicken.setAge(-20 * 60 * 20);
|
||||
chicken->moveTo(x, y, z, yRot, 0);
|
||||
level->addEntity(chicken);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
level->addParticle(PARTICLETYPE(snowballpoof), x, y, z, 0, 0, 0);
|
||||
|
||||
if (!level->isClientSide)
|
||||
remove();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_ENTITY_PROJECTILE__ThrownEgg_H__*/
|
||||
16
src/world/food/FoodConstants.h
Executable file
16
src/world/food/FoodConstants.h
Executable file
@@ -0,0 +1,16 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_FOOD__FoodConstants_H__
|
||||
#define NET_MINECRAFT_WORLD_FOOD__FoodConstants_H__
|
||||
|
||||
//package net.minecraft.world.food;
|
||||
|
||||
class FoodConstants
|
||||
{
|
||||
public:
|
||||
static const int MAX_FOOD = 20;
|
||||
// number of game ticks to change health because of food
|
||||
static const int HEALTH_TICK_COUNT = 80;
|
||||
static const int HEALTH_TICK_COUNT_SIMPLE = 5;
|
||||
static const int HEAL_LEVEL = 18;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_FOOD__FoodConstants_H__*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user