Skip to content
Draft
Binary file modified web-build/data/images/gui/items.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified web-build/data/images/terrain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion web-build/src/client/renderer/entity/ItemRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static const signed short _155[] = {34, 36, 35, -1, -1, -1, -1, -1, -1, -1, -1,
static const signed short _263[] = {230, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
static const signed short _351[] = {-1, 152, 154, -1, 193, 215, 216, -1, -1, 217, 218, 219, 220, 221, 222, 144};

static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, 21, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, 148, 131, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197};
static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197};

#define IRMAPCASE(x) case x: return _##x [item->getAuxValue() & 15]

Expand Down
4 changes: 3 additions & 1 deletion web-build/src/world/entity/EntityRendererId.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ enum EntityRendererId {
ER_THROWNEGG_RENDERER,
ER_SNOWBALL_RENDERER,
ER_PAINTING_RENDERER,
ER_FALLINGTILE_RENDERER
ER_FALLINGTILE_RENDERER,
ER_SLIME_RENDERER,
ER_ENDERMAN_RENDERER
};

#endif /*NET_MINECRAFT_WORLD_ENTITY__EntityRendererId_H__*/
2 changes: 2 additions & 0 deletions web-build/src/world/entity/EntityTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class MobTypes {
static const int Skeleton = 34;
static const int Spider = 35;
static const int PigZombie = 36;
static const int Slime = 37;
static const int Enderman = 38;
};

struct ParticleType {
Expand Down
6 changes: 6 additions & 0 deletions web-build/src/world/entity/MobFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ class MobFactory {
case MobTypes::PigZombie:
mob = new PigZombie(level);
break;
case MobTypes::Slime:
mob = new Slime(level);
break;
case MobTypes::Enderman:
mob = new Enderman(level);
break;
default:
LOGE("Unknown mob type requested: %d\n", mobType);
break;
Expand Down
6 changes: 6 additions & 0 deletions web-build/src/world/entity/animal/Sheep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ void Sheep::dropDeathLoot(/* bool wasKilledByPlayer, int playerBonusLevel*/ )
// killing a non-sheared sheep will drop a single block of cloth
spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 0);
}

// Drop 0-2 raw mutton
int muttonCount = random.nextInt(3);
for (int i = 0; i < muttonCount; i++) {
spawnAtLocation(Item::mutton_raw->id, 1);
}
}

int Sheep::getDeathLoot()
Expand Down
244 changes: 244 additions & 0 deletions web-build/src/world/entity/monster/Enderman.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#include "Enderman.h"

#include "../../item/Item.h"
#include "../../level/Level.h"
#include "../../level/material/Material.h"
#include "../../level/tile/Tile.h"
#include "../../../util/Mth.h"
#include "../EntityTypes.h"
#include "../player/Player.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"

Enderman::Enderman(Level* level)
: super(level),
carriedBlock(0),
teleportCooldown(0),
waterDamageTick(0),
isAngry(false)
{
entityRendererId = ER_ENDERMAN_RENDERER;
this->textureName = "mob/enderman.png";

this->setSize(0.6f, 2.9f);
runSpeed = 0.5f;
attackDamage = 7;

targetSelector = new GoalSelector();
targetSelector->addGoal(1, new HurtByTargetGoal(this, false));

goalSelector = new GoalSelector();
goalSelector->addGoal(2, new MeleeAttackGoal(this, runSpeed, false, 0));
goalSelector->addGoal(7, new RandomStrollGoal(this, runSpeed));

moveControl = new MoveControl(this);
jumpControl = new JumpControl(this);
}

Enderman::~Enderman() {
delete goalSelector;
delete targetSelector;

delete moveControl;
delete jumpControl;
}

int Enderman::getMaxHealth() {
return 40;
}

void Enderman::aiStep() {
super::aiStep();
}

void Enderman::tick() {
super::tick();

if (level->isClientSide) return;

// Take damage from water
if (++waterDamageTick >= 20) {
waterDamageTick = 0;
if (isInWater()) {
hurt(NULL, 1);
teleportRandomly();
}
}

// Try to teleport away if hurt
if (teleportCooldown > 0) {
teleportCooldown--;
}

// If angry, occasionally teleport towards target
if (isAngry && attackTargetId != 0 && teleportCooldown <= 0) {
Entity* target = level->getEntity(attackTargetId);
if (target != NULL && distanceTo(target) > 4.0f) {
teleportTowards(target);
teleportCooldown = 30;
}
}

// Pick up a random block occasionally
if (carriedBlock == 0 && random.nextInt(200) == 0) {
int bx = Mth::floor(x) + random.nextInt(3) - 1;
int by = Mth::floor(y) + random.nextInt(2);
int bz = Mth::floor(z) + random.nextInt(3) - 1;
int tile = level->getTile(bx, by, bz);
if (tile == ((Tile*)Tile::grass)->id || tile == ((Tile*)Tile::dirt)->id || tile == ((Tile*)Tile::sand)->id) {
carriedBlock = tile;
level->setTile(bx, by, bz, 0);
}
}
}

int Enderman::getEntityTypeId() const {
return MobTypes::Enderman;
}

void Enderman::die(Entity* source) {
// Place carried block back
if (carriedBlock != 0 && !level->isClientSide) {
int bx = Mth::floor(x);
int by = Mth::floor(y);
int bz = Mth::floor(z);
if (level->isEmptyTile(bx, by, bz)) {
level->setTile(bx, by, bz, carriedBlock);
}
carriedBlock = 0;
}
super::die(source);
}

int Enderman::getAttackDamage(Entity* target) {
return attackDamage;
}

bool Enderman::hurt(Entity* source, int dmg) {
if (super::hurt(source, dmg)) {
if (source != NULL) {
isAngry = true;
attackTargetId = source->entityId;
}
// Try to teleport when hurt
if (random.nextInt(3) == 0) {
teleportRandomly();
}
return true;
}
return false;
}

Entity* Enderman::findAttackTarget() {
Player* player = level->getNearestPlayer(this, 64);
if (player != NULL && isLookedAt(player)) {
isAngry = true;
return player;
}
if (isAngry) {
return super::findAttackTarget();
}
return NULL;
}

bool Enderman::isLookedAt(Entity* player) {
float dx = x - player->x;
float dy = (y + bbHeight) - (player->y + player->getHeadHeight());
float dz = z - player->z;
float dist = Mth::sqrt(dx * dx + dy * dy + dz * dz);
if (dist > 64) return false;

// Rough check: see if the player's look direction points at us
float lookX = -Mth::sin(player->yRot * Mth::DEGRAD) * Mth::cos(player->xRot * Mth::DEGRAD);
float lookY = -Mth::sin(player->xRot * Mth::DEGRAD);
float lookZ = Mth::cos(player->yRot * Mth::DEGRAD) * Mth::cos(player->xRot * Mth::DEGRAD);

float ndx = dx / dist;
float ndy = dy / dist;
float ndz = dz / dist;

float dot = lookX * ndx + lookY * ndy + lookZ * ndz;
return dot > 0.9f;
}

void Enderman::checkHurtTarget(Entity* target, float distance) {
if (attackTime <= 0 && distance < 2.5f && target->bb.y1 > bb.y0 && target->bb.y0 < bb.y1) {
attackTime = getAttackTime();
doHurtTarget(target);
}
}

bool Enderman::teleportRandomly() {
float tx = x + (random.nextFloat() - 0.5f) * 32.0f;
float ty = y + (float)(random.nextInt(16) - 8);
float tz = z + (random.nextFloat() - 0.5f) * 32.0f;
return teleportTo(tx, ty, tz);
}

bool Enderman::teleportTowards(Entity* target) {
float dx = target->x - x;
float dz = target->z - z;
float dist = Mth::sqrt(dx * dx + dz * dz);
if (dist < 1.0f) return false;

float tx = x + (dx / dist) * 8.0f + (random.nextFloat() - 0.5f) * 4.0f;
float ty = y + (float)(random.nextInt(8) - 4);
float tz = z + (dz / dist) * 8.0f + (random.nextFloat() - 0.5f) * 4.0f;
return teleportTo(tx, ty, tz);
}

bool Enderman::teleportTo(float tx, float ty, float tz) {
int bx = Mth::floor(tx);
int by = Mth::floor(ty);
int bz = Mth::floor(tz);

// Find solid ground
if (by < 1) by = 1;
if (by > 120) by = 120;

while (by > 1 && level->isEmptyTile(bx, by - 1, bz)) {
by--;
}

if (!level->isEmptyTile(bx, by, bz) || !level->isEmptyTile(bx, by + 1, bz) || !level->isEmptyTile(bx, by + 2, bz)) {
return false;
}

// Check not teleporting into water
if (level->getMaterial(bx, by, bz) == Material::water) {
return false;
}

moveTo(tx, (float)by, tz, yRot, xRot);

level->playSound(this, "mob.endermen.portal", 1.0f, 1.0f);

return true;
}

int Enderman::getDeathLoot() {
return Item::enderPearl->id;
}

void Enderman::dropDeathLoot() {
int count = random.nextInt(2); // 0-1
for (int i = 0; i < count; i++) {
spawnAtLocation(Item::enderPearl->id, 1);
}
}

const char* Enderman::getAmbientSound() {
return "mob.endermen.idle";
}

std::string Enderman::getHurtSound() {
return "mob.endermen.hit";
}

std::string Enderman::getDeathSound() {
return "mob.endermen.death";
}
50 changes: 50 additions & 0 deletions web-build/src/world/entity/monster/Enderman.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef NET_MINECRAFT_WORLD_ENTITY_MONSTER__Enderman_H__
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__Enderman_H__

#include "Monster.h"
#include <string>

class Level;
class Entity;

class Enderman: public Monster
{
typedef Monster super;
public:
Enderman(Level* level);
~Enderman();

int getMaxHealth();
void aiStep();
void tick();
virtual int getEntityTypeId() const;
virtual void die(Entity* source);
virtual int getAttackDamage(Entity* target);
bool hurt(Entity* source, int dmg);

int getCarriedBlock() const { return carriedBlock; }

protected:
int getDeathLoot();
void dropDeathLoot();

Entity* findAttackTarget();
void checkHurtTarget(Entity* target, float distance);

const char* getAmbientSound();
std::string getHurtSound();
std::string getDeathSound();

private:
bool isLookedAt(Entity* player);
bool teleportRandomly();
bool teleportTowards(Entity* target);
bool teleportTo(float tx, float ty, float tz);

int carriedBlock;
int teleportCooldown;
int waterDamageTick;
bool isAngry;
};

#endif /*NET_MINECRAFT_WORLD_ENTITY_MONSTER__Enderman_H__*/
2 changes: 2 additions & 0 deletions web-build/src/world/entity/monster/MonsterInclude.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
#define NET_MINECRAFT_WORLD_ENTITY_MONSTER__MonsterInclude_H__

#include "Creeper.h"
#include "Enderman.h"
#include "Monster.h"
#include "Skeleton.h"
#include "Slime.h"
#include "Spider.h"
#include "Zombie.h"
#include "PigZombie.h"
Expand Down
Loading