the whole game

This commit is contained in:
2026-03-02 22:04:18 +03:00
parent 816e9060b4
commit f0617a5d22
2069 changed files with 581500 additions and 0 deletions

View 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);
// }
//}

View 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__*/

View 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;
}

View 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__*/

View 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__*/

View 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;
}

View 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__ */

View 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;
// }

View 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__*/

View 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);
// }
//

View 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__*/

View 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;
//}

View 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__*/