TU19: merge Minecraft.World/Entities

This commit is contained in:
Tropical 2026-03-21 16:29:02 -05:00
parent 405a87e078
commit 3d3fa566c7
178 changed files with 12204 additions and 4256 deletions

View file

@ -0,0 +1,24 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.effect.h"
#include "AbsoptionMobEffect.h"
AbsoptionMobEffect::AbsoptionMobEffect(int id, bool isHarmful,
eMinecraftColour color)
: MobEffect(id, isHarmful, color) {}
void AbsoptionMobEffect::removeAttributeModifiers(
std::shared_ptr<LivingEntity> entity, BaseAttributeMap* attributes,
int amplifier) {
entity->setAbsorptionAmount(entity->getAbsorptionAmount() -
4 * (amplifier + 1));
MobEffect::removeAttributeModifiers(entity, attributes, amplifier);
}
void AbsoptionMobEffect::addAttributeModifiers(
std::shared_ptr<LivingEntity> entity, BaseAttributeMap* attributes,
int amplifier) {
entity->setAbsorptionAmount(entity->getAbsorptionAmount() +
4 * (amplifier + 1));
MobEffect::addAttributeModifiers(entity, attributes, amplifier);
}

View file

@ -0,0 +1,15 @@
#pragma once
class LivingEntity;
#include "MobEffect.h"
class AbsoptionMobEffect : public MobEffect {
public:
AbsoptionMobEffect(int id, bool isHarmful, eMinecraftColour color);
void removeAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes, int amplifier);
void addAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes, int amplifier);
};

View file

@ -0,0 +1,16 @@
#include "../Platform/stdafx.h"
#include "AttackDamageMobEffect.h"
AttackDamageMobEffect::AttackDamageMobEffect(int id, bool isHarmful,
eMinecraftColour color)
: MobEffect(id, isHarmful, color) {}
double AttackDamageMobEffect::getAttributeModifierValue(
int amplifier, AttributeModifier* original) {
if (id == MobEffect::weakness->id) {
return -0.5f * (amplifier + 1);
} else {
return 1.3 * (amplifier + 1);
}
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "MobEffect.h"
class AttributeModifier;
class AttackDamageMobEffect : public MobEffect {
public:
AttackDamageMobEffect(int id, bool isHarmful, eMinecraftColour color);
double getAttributeModifierValue(int amplifier,
AttributeModifier* original);
};

View file

@ -1,31 +0,0 @@
#include "../Platform/stdafx.h"
#include "Mobs/BossMob.h"
#include "BossMobPart.h"
BossMobPart::BossMobPart(BossMob* bossMob, const std::wstring& id, float w,
float h)
: Entity(bossMob->level), bossMob(bossMob), id(id) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
setSize(w, h);
}
void BossMobPart::defineSynchedData() {}
void BossMobPart::readAdditionalSaveData(CompoundTag* tag) {}
void BossMobPart::addAdditonalSaveData(CompoundTag* tag) {}
bool BossMobPart::isPickable() { return true; }
bool BossMobPart::hurt(DamageSource* source, int damage) {
return bossMob->hurt(
std::dynamic_pointer_cast<BossMobPart>(shared_from_this()), source,
damage);
}
bool BossMobPart::is(std::shared_ptr<Entity> other) {
return shared_from_this() == other || bossMob == other.get();
}

View file

@ -1,27 +0,0 @@
#pragma once
#include "Entity.h"
class Level;
class BossMob;
class BossMobPart : public Entity {
public:
eINSTANCEOF GetType() { return eTYPE_BOSS_MOB_PART; };
public:
BossMob* bossMob;
const std::wstring id;
BossMobPart(BossMob* bossMob, const std::wstring& id, float w, float h);
protected:
virtual void defineSynchedData();
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void addAdditonalSaveData(CompoundTag* tag);
public:
virtual bool isPickable();
virtual bool hurt(DamageSource* source, int damage);
virtual bool is(std::shared_ptr<Entity> other);
};

View file

@ -1,8 +1,8 @@
#include "../Platform/stdafx.h"
#include "Enemy.h"
const int Enemy::XP_REWARD_NONE = 0;
const int Enemy::XP_REWARD_SMALL = 3;
const int Enemy::XP_REWARD_MEDIUM = 5;
const int Enemy::XP_REWARD_LARGE = 10;
const int Enemy::XP_REWARD_HUGE = 20;
EntitySelector* Enemy::ENEMY_SELECTOR = new Enemy::EnemyEntitySelector();
bool Enemy::EnemyEntitySelector::matches(std::shared_ptr<Entity> entity) const {
return (entity != NULL) && entity->instanceof(eTYPE_ENEMY);
}

View file

@ -1,13 +1,19 @@
#pragma once
#include "Mobs/Creature.h"
class Level;
#include "EntitySelector.h"
class Enemy : public Creature {
public:
static const int XP_REWARD_NONE;
static const int XP_REWARD_SMALL;
static const int XP_REWARD_MEDIUM;
static const int XP_REWARD_LARGE;
static const int XP_REWARD_HUGE;
class EnemyEntitySelector : public EntitySelector {
bool matches(std::shared_ptr<Entity> entity) const;
};
static const int XP_REWARD_NONE = 0;
static const int XP_REWARD_SMALL = 3;
static const int XP_REWARD_MEDIUM = 5;
static const int XP_REWARD_LARGE = 10;
static const int XP_REWARD_HUGE = 20;
static const int XP_REWARD_BOSS = 50;
static EntitySelector* ENEMY_SELECTOR;
};

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
#include <pthread.h>
#endif
class Mob;
class LivingEntity;
class LightningBolt;
class ItemEntity;
class EntityPos;
@ -21,6 +21,7 @@ class Random;
class Level;
class CompoundTag;
class DamageSource;
class Explosion;
// 4J Stu Added this mainly to allow is to record telemetry for player deaths
enum EEntityDamageType {
@ -48,7 +49,15 @@ public:
// 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts
virtual eINSTANCEOF GetType() = 0;
inline bool instanceof(eINSTANCEOF super) {
return eTYPE_DERIVED_FROM(super, GetType());
}
inline static bool instanceof(eINSTANCEOF type, eINSTANCEOF super) {
return eTYPE_DERIVED_FROM(super, type);
}
public:
static const std::wstring RIDING_TAG;
static const short TOTAL_AIR_SUPPLY = 20 * 15;
private:
@ -63,6 +72,7 @@ public:
std::weak_ptr<Entity> rider; // Changed to weak to avoid circular
// dependency between rider/riding entity
std::shared_ptr<Entity> riding;
bool forcedLoading;
Level* level;
double xo, yo, zo;
@ -89,6 +99,7 @@ public:
float walkDistO;
float walkDist;
float moveDist;
float fallDistance;
private:
@ -120,10 +131,6 @@ public:
private:
bool firstTick;
public:
std::wstring customTextureUrl;
std::wstring customTextureUrl2;
protected:
bool fireImmune;
@ -135,7 +142,7 @@ private:
static const int DATA_SHARED_FLAGS_ID = 0;
static const int FLAG_ONFIRE = 0;
static const int FLAG_SNEAKING = 1;
static const int FLAG_RIDING = 2;
// static const int FLAG_ = 2;
static const int FLAG_SPRINTING = 3;
static const int FLAG_USING_ITEM = 4;
static const int FLAG_INVISIBLE = 5;
@ -153,12 +160,29 @@ public:
int xp, yp, zp, xRotp, yRotp;
bool noCulling;
bool hasImpulse;
int changingDimensionDelay;
protected:
bool isInsidePortal;
int portalTime;
public:
int dimension;
protected:
int portalEntranceDir;
private:
bool invulnerable;
std::wstring uuid;
protected:
// 4J Added so that client side simulations on the host are not affected by
// zero-lag
bool m_ignoreVerticalCollisions;
bool m_ignorePortal;
public:
Entity(Level* level,
bool useSmallId = true); // 4J - added useSmallId parameter
@ -166,7 +190,7 @@ public:
protected:
// 4J - added for common ctor code
void _init(bool useSmallId);
void _init(bool useSmallId, Level* level);
protected:
virtual void defineSynchedData() = 0;
@ -204,6 +228,7 @@ public:
void interpolateTurn(float xo, float yo);
virtual void tick();
virtual void baseTick();
virtual int getPortalWaitTime();
protected:
void lavaHurt();
@ -272,7 +297,7 @@ protected:
public:
// 4J Added damageSource param to enable telemetry on player deaths
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
bool intersects(double x0, double y0, double z0, double x1, double y1,
double z1);
virtual bool isPickable();
@ -281,18 +306,24 @@ public:
virtual void awardKillScore(std::shared_ptr<Entity> victim, int score);
virtual bool shouldRender(Vec3* c);
virtual bool shouldRenderAtSqrDistance(double distance);
virtual int getTexture(); // 4J - changed from std::wstring to int
virtual bool isCreativeModeAllowed();
bool saveAsMount(CompoundTag* entityTag);
bool save(CompoundTag* entityTag);
void saveWithoutId(CompoundTag* entityTag);
virtual void load(CompoundTag* tag);
protected:
virtual bool repositionEntityAfterLoad();
const std::wstring getEncodeId();
public:
virtual void readAdditionalSaveData(CompoundTag* tag) = 0;
virtual void addAdditonalSaveData(CompoundTag* tag) = 0;
/**
* Called after load() has finished and the entity has been added to the
* world
*/
virtual void onLoadedFromSave();
protected:
ListTag<DoubleTag>* newDoubleList(unsigned int number, double firstValue,
@ -317,20 +348,15 @@ public:
virtual double getRidingHeight();
virtual double getRideHeight();
virtual void ride(std::shared_ptr<Entity> e);
virtual void findStandUpPosition(
std::shared_ptr<Entity>
vehicle); // 4J Stu - Brought forward from 12w36 to fix #46282 -
// TU5: Gameplay: Exiting the minecart in a tight
// corridor damages the player
virtual void lerpTo(double x, double y, double z, float yRot, float xRot,
int steps);
virtual float getPickRadius();
virtual Vec3* getLookAngle();
virtual void handleInsidePortal();
virtual int getDimensionChangingDelay();
virtual void lerpMotion(double xd, double yd, double zd);
virtual void handleEntityEvent(uint8_t eventId);
virtual void animateHurt();
virtual void prepareCustomTextures();
virtual ItemInstanceArray getEquipmentSlots(); // ItemInstance[]
virtual void setEquippedSlot(
int slot, std::shared_ptr<ItemInstance>
@ -369,7 +395,7 @@ public:
void setAirSupply(int supply);
virtual void thunderHit(const LightningBolt* lightningBolt);
virtual void killed(std::shared_ptr<Mob> mob);
virtual void killed(std::shared_ptr<LivingEntity> mob);
protected:
bool checkInTile(double x, double y, double z);
@ -379,9 +405,6 @@ public:
virtual std::wstring getAName();
// TU9
bool skipAttackInteraction(std::shared_ptr<Entity> source) { return false; }
// 4J - added to manage allocation of small ids
private:
// Things also added here to be able to manage the concept of a number of
@ -423,8 +446,25 @@ public:
virtual float getYHeadRot();
virtual void setYHeadRot(float yHeadRot);
virtual bool isAttackable();
virtual bool skipAttackInteraction(std::shared_ptr<Entity> source);
virtual bool isInvulnerable();
virtual void copyPosition(std::shared_ptr<Entity> target);
virtual void restoreFrom(std::shared_ptr<Entity> oldEntity,
bool teleporting);
virtual void changeDimension(int i);
virtual float getTileExplosionResistance(Explosion* explosion, Level* level,
int x, int y, int z, Tile* tile);
virtual bool shouldTileExplode(Explosion* explosion, Level* level, int x,
int y, int z, int id, float power);
virtual int getMaxFallDistance();
virtual int getPortalEntranceDir();
virtual bool isIgnoringTileTriggers();
virtual bool displayFireAnimation();
virtual void setUUID(const std::wstring& UUID);
virtual std::wstring getUUID();
virtual bool isPushedByWater();
virtual std::wstring getDisplayName();
virtual std::wstring getNetworkName(); // 4J: Added
private:
unsigned int m_uiAnimOverrideBitmask;

View file

@ -4,36 +4,58 @@
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.network.packet.h"
// EntityDamageSource::EntityDamageSource(const std::wstring &msgId,
// std::shared_ptr<Entity> entity) : DamageSource(msgId)
EntityDamageSource::EntityDamageSource(ChatPacket::EChatPacketMessage msgId,
std::shared_ptr<Entity> entity)
: DamageSource(msgId) {
// EntityDamageSource::EntityDamageSource(const wstring &msgId,
// shared_ptr<Entity> entity) : DamageSource(msgId)
EntityDamageSource::EntityDamageSource(
ChatPacket::EChatPacketMessage msgId,
ChatPacket::EChatPacketMessage msgWithItemId,
std::shared_ptr<Entity> entity)
: DamageSource(msgId, msgWithItemId) {
this->entity = entity;
}
std::shared_ptr<Entity> EntityDamageSource::getEntity() { return entity; }
// std::wstring
// EntityDamageSource::getLocalizedDeathMessage(std::shared_ptr<Player> player)
// wstring EntityDamageSource::getLocalizedDeathMessage(shared_ptr<Player>
// player)
//{
// return L"death." + msgId + player->name + entity->getAName();
// //return I18n.get("death." + msgId, player.name, entity.getAName());
// }
std::shared_ptr<ChatPacket> EntityDamageSource::getDeathMessagePacket(
std::shared_ptr<Player> player) {
std::shared_ptr<LivingEntity> player) {
std::shared_ptr<ItemInstance> held =
(entity != NULL) && entity->instanceof(eTYPE_LIVINGENTITY)
? std::dynamic_pointer_cast<LivingEntity>(entity)->getCarriedItem()
: nullptr;
std::wstring additional = L"";
if (entity->GetType() == eTYPE_SERVERPLAYER) {
std::shared_ptr<Player> sourcePlayer =
std::dynamic_pointer_cast<Player>(entity);
if (sourcePlayer != NULL) additional = sourcePlayer->name;
if (entity->instanceof(eTYPE_SERVERPLAYER)) {
additional = std::dynamic_pointer_cast<Player>(entity)->name;
} else if (entity->instanceof(eTYPE_MOB)) {
std::shared_ptr<Mob> mob = std::dynamic_pointer_cast<Mob>(entity);
if (mob->hasCustomName()) {
additional = mob->getCustomName();
}
}
if ((held != NULL) && held->hasCustomHoverName()) {
return std::shared_ptr<ChatPacket>(new ChatPacket(
player->getNetworkName(), m_msgWithItemId, entity->GetType(),
additional, held->getHoverName()));
} else {
return std::shared_ptr<ChatPacket>(new ChatPacket(
player->getNetworkName(), m_msgId, entity->GetType(), additional));
}
return std::shared_ptr<ChatPacket>(
new ChatPacket(player->name, m_msgId, entity->GetType(), additional));
}
bool EntityDamageSource::scalesWithDifficulty() {
return entity != NULL && std::dynamic_pointer_cast<Mob>(entity) &&
!(std::dynamic_pointer_cast<Player>(entity));
return (entity != NULL) && entity->instanceof(eTYPE_LIVINGENTITY) &&
!entity->instanceof(eTYPE_PLAYER);
}
// 4J: Copy function
DamageSource* EntityDamageSource::copy() {
return new EntityDamageSource(*this);
}

View file

@ -13,6 +13,7 @@ public:
// EntityDamageSource(const std::wstring &msgId, std::shared_ptr<Entity>
// entity);
EntityDamageSource(ChatPacket::EChatPacketMessage msgId,
ChatPacket::EChatPacketMessage msgWithItemId,
std::shared_ptr<Entity> entity);
virtual ~EntityDamageSource() {}
@ -22,7 +23,9 @@ public:
// virtual std::wstring getLocalizedDeathMessage(std::shared_ptr<Player>
// player);
virtual std::shared_ptr<ChatPacket> getDeathMessagePacket(
std::shared_ptr<Player> player);
std::shared_ptr<LivingEntity> player);
virtual bool scalesWithDifficulty();
virtual DamageSource* copy();
};

View file

@ -0,0 +1,42 @@
#include "../Platform/stdafx.h"
#include "../Containers/Container.h"
#include "EntitySelector.h"
const EntitySelector* EntitySelector::ENTITY_STILL_ALIVE =
new AliveEntitySelector();
const EntitySelector* EntitySelector::CONTAINER_ENTITY_SELECTOR =
new ContainerEntitySelector();
bool AliveEntitySelector::matches(std::shared_ptr<Entity> entity) const {
return entity->isAlive();
}
bool ContainerEntitySelector::matches(std::shared_ptr<Entity> entity) const {
return (std::dynamic_pointer_cast<Container>(entity) != NULL) &&
entity->isAlive();
}
MobCanWearArmourEntitySelector::MobCanWearArmourEntitySelector(
std::shared_ptr<ItemInstance> item) {
this->item = item;
}
bool MobCanWearArmourEntitySelector::matches(
std::shared_ptr<Entity> entity) const {
if (!entity->isAlive()) return false;
if (!entity->instanceof(eTYPE_LIVINGENTITY)) return false;
std::shared_ptr<LivingEntity> mob =
std::dynamic_pointer_cast<LivingEntity>(entity);
if (mob->getCarried(Mob::getEquipmentSlotForItem(item)) != NULL)
return false;
if (mob->instanceof(eTYPE_MOB)) {
return std::dynamic_pointer_cast<Mob>(mob)->canPickUpLoot();
} else if (mob->instanceof(eTYPE_PLAYER)) {
return true;
}
return false;
}

View file

@ -0,0 +1,28 @@
#pragma once
class EntitySelector {
public:
static const EntitySelector* ENTITY_STILL_ALIVE;
static const EntitySelector* CONTAINER_ENTITY_SELECTOR;
virtual bool matches(std::shared_ptr<Entity> entity) const = 0;
};
class AliveEntitySelector : public EntitySelector {
public:
bool matches(std::shared_ptr<Entity> entity) const;
};
class ContainerEntitySelector : public EntitySelector {
public:
bool matches(std::shared_ptr<Entity> entity) const;
};
class MobCanWearArmourEntitySelector : public EntitySelector {
private:
std::shared_ptr<ItemInstance> item;
public:
MobCanWearArmourEntitySelector(std::shared_ptr<ItemInstance> item);
bool matches(std::shared_ptr<Entity> entity) const;
};

View file

@ -0,0 +1,158 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.item.h"
#include "../Headers/net.minecraft.world.level.h"
#include "FireworksRocketEntity.h"
FireworksRocketEntity::FireworksRocketEntity(Level* level) : Entity(level) {
defineSynchedData();
life = 0;
lifetime = 0;
setSize(0.25f, 0.25f);
}
void FireworksRocketEntity::defineSynchedData() {
entityData->defineNULL(DATA_ID_FIREWORKS_ITEM, NULL);
}
bool FireworksRocketEntity::shouldRenderAtSqrDistance(double distance) {
return distance < 64 * 64;
}
FireworksRocketEntity::FireworksRocketEntity(
Level* level, double x, double y, double z,
std::shared_ptr<ItemInstance> sourceItem)
: Entity(level) {
defineSynchedData();
life = 0;
setSize(0.25f, 0.25f);
setPos(x, y, z);
heightOffset = 0;
int flightCount = 1;
if (sourceItem != NULL && sourceItem->hasTag()) {
entityData->set(DATA_ID_FIREWORKS_ITEM, sourceItem);
CompoundTag* tag = sourceItem->getTag();
CompoundTag* compound = tag->getCompound(FireworksItem::TAG_FIREWORKS);
if (compound != NULL) {
flightCount += compound->getByte(FireworksItem::TAG_FLIGHT);
}
}
xd = random->nextGaussian() * .001;
zd = random->nextGaussian() * .001;
yd = 0.05;
lifetime = (SharedConstants::TICKS_PER_SECOND / 2) * flightCount +
random->nextInt(6) + random->nextInt(7);
}
void FireworksRocketEntity::lerpMotion(double xd, double yd, double zd) {
xd = xd;
yd = yd;
zd = zd;
if (xRotO == 0 && yRotO == 0) {
double sd = Mth::sqrt(xd * xd + zd * zd);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, sd) * 180 / PI);
}
}
void FireworksRocketEntity::tick() {
xOld = x;
yOld = y;
zOld = z;
Entity::tick();
xd *= 1.15;
zd *= 1.15;
yd += .04;
move(xd, yd, zd);
double sd = Mth::sqrt(xd * xd + zd * zd);
yRot = (float)(atan2(xd, zd) * 180 / PI);
xRot = (float)(atan2(yd, sd) * 180 / 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;
if (!level->isClientSide) {
if (life == 0) {
level->playEntitySound(shared_from_this(),
eSoundType_FIREWORKS_LAUNCH, 3, 1);
}
}
life++;
if (level->isClientSide && (life % 2) < 2) {
level->addParticle(eParticleType_fireworksspark, x, y - .3, z,
random->nextGaussian() * .05, -yd * .5,
random->nextGaussian() * .05);
}
if (!level->isClientSide && life > lifetime) {
level->broadcastEntityEvent(shared_from_this(),
EntityEvent::FIREWORKS_EXPLODE);
remove();
}
}
void FireworksRocketEntity::handleEntityEvent(uint8_t eventId) {
if (eventId == EntityEvent::FIREWORKS_EXPLODE && level->isClientSide) {
std::shared_ptr<ItemInstance> sourceItem =
entityData->getItemInstance(DATA_ID_FIREWORKS_ITEM);
CompoundTag* tag = NULL;
if (sourceItem != NULL && sourceItem->hasTag()) {
tag =
sourceItem->getTag()->getCompound(FireworksItem::TAG_FIREWORKS);
}
level->createFireworks(x, y, z, xd, yd, zd, tag);
}
Entity::handleEntityEvent(eventId);
}
void FireworksRocketEntity::addAdditonalSaveData(CompoundTag* tag) {
tag->putInt(L"Life", life);
tag->putInt(L"LifeTime", lifetime);
std::shared_ptr<ItemInstance> itemInstance =
entityData->getItemInstance(DATA_ID_FIREWORKS_ITEM);
if (itemInstance != NULL) {
CompoundTag* itemTag = new CompoundTag();
itemInstance->save(itemTag);
tag->putCompound(L"FireworksItem", itemTag);
}
}
void FireworksRocketEntity::readAdditionalSaveData(CompoundTag* tag) {
life = tag->getInt(L"Life");
lifetime = tag->getInt(L"LifeTime");
CompoundTag* itemTag = tag->getCompound(L"FireworksItem");
if (itemTag != NULL) {
std::shared_ptr<ItemInstance> fromTag = ItemInstance::fromTag(itemTag);
if (fromTag != NULL) {
entityData->set(DATA_ID_FIREWORKS_ITEM, fromTag);
}
}
}
float FireworksRocketEntity::getShadowHeightOffs() { return 0; }
float FireworksRocketEntity::getBrightness(float a) {
return Entity::getBrightness(a);
}
int FireworksRocketEntity::getLightColor(float a) {
return Entity::getLightColor(a);
}
bool FireworksRocketEntity::isAttackable() { return false; }

View file

@ -0,0 +1,40 @@
#pragma once
#include "Entity.h"
class FireworksRocketEntity : public Entity {
public:
eINSTANCEOF GetType() { return eTYPE_FIREWORKS_ROCKET; }
static Entity* create(Level* level) {
return new FireworksRocketEntity(level);
}
private:
static const int DATA_ID_FIREWORKS_ITEM = 8;
int life;
int lifetime;
// constructor needed for level loader
public:
FireworksRocketEntity(Level* level);
protected:
virtual void defineSynchedData();
public:
virtual bool shouldRenderAtSqrDistance(double distance);
FireworksRocketEntity(Level* level, double x, double y, double z,
std::shared_ptr<ItemInstance> sourceItem);
virtual void lerpMotion(double xd, double yd, double zd);
virtual void tick();
virtual void handleEntityEvent(uint8_t eventId);
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual float getShadowHeightOffs();
virtual float getBrightness(float a);
virtual int getLightColor(float a);
virtual bool isAttackable();
};

View file

@ -11,6 +11,11 @@ void FlyingMob::causeFallDamage(float distance) {
// not trigger the "fallOn" tile calls (such as trampling crops)
}
void FlyingMob::checkFallDamage(double ya, bool onGround) {
// this method is empty because flying creatures should
// not trigger the "fallOn" tile calls (such as trampling crops)
}
void FlyingMob::travel(float xa, float ya) {
if (isInWater()) {
moveRelative(xa, ya, 0.02f);

View file

@ -10,6 +10,7 @@ public:
protected:
virtual void causeFallDamage(float distance);
virtual void checkFallDamage(double ya, bool onGround);
public:
virtual void travel(float xa, float ya);

View file

@ -11,22 +11,16 @@ void HangingEntity::_init(Level* level) {
checkInterval = 0;
dir = 0;
xTile = yTile = zTile = 0;
}
HangingEntity::HangingEntity(Level* level) : Entity(level) {
_init(level);
this->heightOffset = 0;
this->setSize(0.5f, 0.5f);
}
HangingEntity::HangingEntity(Level* level) : Entity(level) { _init(level); }
HangingEntity::HangingEntity(Level* level, int xTile, int yTile, int zTile,
int dir)
: Entity(level) {
_init(level);
// motive = NULL;
this->heightOffset = 0;
this->setSize(0.5f, 0.5f);
this->xTile = xTile;
this->yTile = yTile;
this->zTile = zTile;
@ -34,7 +28,7 @@ HangingEntity::HangingEntity(Level* level, int xTile, int yTile, int zTile,
void HangingEntity::setDir(int dir) {
this->dir = dir;
this->yRotO = this->yRot = (float)(dir * 90);
yRotO = yRot = (float)(dir * 90);
float w = (float)getWidth();
float h = (float)getHeight();
@ -68,7 +62,7 @@ void HangingEntity::setDir(int dir) {
if (dir == Direction::EAST) z -= offs(getWidth());
y += offs(getHeight());
this->setPos(x, y, z);
setPos(x, y, z);
float ss = -(0.5f / 16.0f);
@ -91,12 +85,14 @@ float HangingEntity::offs(int w) {
}
void HangingEntity::tick() {
if (checkInterval++ == 20 * 5 && !level->isClientSide) // isClientSide)
{
xo = x;
yo = y;
zo = z;
if (checkInterval++ == 20 * 5 && !level->isClientSide) {
checkInterval = 0;
if (!removed && !survives()) {
remove();
dropItem();
dropItem(nullptr);
}
}
}
@ -138,7 +134,7 @@ bool HangingEntity::survives() {
AUTO_VAR(itEnd, entities->end());
for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) {
std::shared_ptr<Entity> e = (*it);
if (std::dynamic_pointer_cast<HangingEntity>(e) != NULL) {
if (e->instanceof(eTYPE_HANGING_ENTITY)) {
return false;
}
}
@ -159,12 +155,14 @@ bool HangingEntity::skipAttackInteraction(std::shared_ptr<Entity> source) {
return false;
}
bool HangingEntity::hurt(DamageSource* source, int damage) {
bool HangingEntity::hurt(DamageSource* source, float damage) {
if (isInvulnerable()) return false;
if (!removed && !level->isClientSide) {
if (dynamic_cast<EntityDamageSource*>(source) != NULL) {
std::shared_ptr<Entity> sourceEntity = source->getDirectEntity();
if (std::dynamic_pointer_cast<Player>(sourceEntity) != NULL &&
if ((sourceEntity != NULL) &&
sourceEntity->instanceof(eTYPE_PLAYER) &&
!std::dynamic_pointer_cast<Player>(sourceEntity)
->isAllowedToHurtEntity(shared_from_this())) {
return false;
@ -176,8 +174,9 @@ bool HangingEntity::hurt(DamageSource* source, int damage) {
std::shared_ptr<Player> player = nullptr;
std::shared_ptr<Entity> e = source->getEntity();
if (e != NULL && ((e->GetType() & eTYPE_PLAYER) !=
0)) // check if it's serverplayer or player
if ((e != NULL) &&
e->instanceof(
eTYPE_PLAYER)) // check if it's serverplayer or player
{
player = std::dynamic_pointer_cast<Player>(e);
}
@ -186,7 +185,7 @@ bool HangingEntity::hurt(DamageSource* source, int damage) {
return true;
}
dropItem();
dropItem(nullptr);
}
return true;
}
@ -195,14 +194,14 @@ bool HangingEntity::hurt(DamageSource* source, int damage) {
void HangingEntity::move(double xa, double ya, double za, bool noEntityCubes) {
if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) {
remove();
dropItem();
dropItem(nullptr);
}
}
void HangingEntity::push(double xa, double ya, double za) {
if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) {
remove();
dropItem();
dropItem(nullptr);
}
}
@ -253,3 +252,5 @@ void HangingEntity::readAdditionalSaveData(CompoundTag* tag) {
zTile = tag->getInt(L"TileZ");
setDir(dir);
}
bool HangingEntity::repositionEntityAfterLoad() { return false; }

View file

@ -9,7 +9,6 @@ public:
private:
void _init(Level* level);
float offs(int w);
int checkInterval;
// eINSTANCEOF eType;
@ -24,12 +23,16 @@ public:
HangingEntity(Level* level);
HangingEntity(Level* level, int xTile, int yTile, int zTile, int dir);
void setDir(int dir);
bool survives();
virtual bool survives();
private:
float offs(int w);
public:
virtual void tick();
virtual bool isPickable();
virtual bool skipAttackInteraction(std::shared_ptr<Entity> source);
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
virtual void move(
double xa, double ya, double za,
bool noEntityCubes = false); // 4J - added noEntityCubes parameter
@ -39,5 +42,8 @@ public:
virtual int getWidth() = 0;
virtual int getHeight() = 0;
virtual void dropItem() = 0;
virtual void dropItem(std::shared_ptr<Entity> causedBy) = 0;
protected:
virtual bool repositionEntityAfterLoad();
};

View file

@ -0,0 +1,16 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "HealthBoostMobEffect.h"
HealthBoostMobEffect::HealthBoostMobEffect(int id, bool isHarmful,
eMinecraftColour color)
: MobEffect(id, isHarmful, color) {}
void HealthBoostMobEffect::removeAttributeModifiers(
std::shared_ptr<LivingEntity> entity, BaseAttributeMap* attributes,
int amplifier) {
MobEffect::removeAttributeModifiers(entity, attributes, amplifier);
if (entity->getHealth() > entity->getMaxHealth()) {
entity->setHealth(entity->getMaxHealth());
}
}

View file

@ -0,0 +1,14 @@
#pragma once
#include "MobEffect.h"
class LivingEntity;
class BaseAttributeMap;
class HealthBoostMobEffect : public MobEffect {
public:
HealthBoostMobEffect(int id, bool isHarmful, eMinecraftColour color);
void removeAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes, int amplifier);
};

View file

@ -4,13 +4,14 @@
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.network.packet.h"
// IndirectEntityDamageSource::IndirectEntityDamageSource(const std::wstring
// &msgId, std::shared_ptr<Entity> entity, std::shared_ptr<Entity> owner) :
// IndirectEntityDamageSource::IndirectEntityDamageSource(const wstring &msgId,
// shared_ptr<Entity> entity, shared_ptr<Entity> owner) :
// EntityDamageSource(msgId, entity)
IndirectEntityDamageSource::IndirectEntityDamageSource(
ChatPacket::EChatPacketMessage msgId, std::shared_ptr<Entity> entity,
std::shared_ptr<Entity> owner)
: EntityDamageSource(msgId, entity) {
ChatPacket::EChatPacketMessage msgId,
ChatPacket::EChatPacketMessage msgWithItemId,
std::shared_ptr<Entity> entity, std::shared_ptr<Entity> owner)
: EntityDamageSource(msgId, msgWithItemId, entity) {
this->owner = owner;
}
@ -23,8 +24,8 @@ std::shared_ptr<Entity> IndirectEntityDamageSource::getEntity() {
return owner;
}
// std::wstring
// IndirectEntityDamageSource::getLocalizedDeathMessage(std::shared_ptr<Player>
// wstring
// IndirectEntityDamageSource::getLocalizedDeathMessage(shared_ptr<Player>
// player)
//{
// return L"death." + msgId + player->name + owner->getAName();
@ -32,7 +33,11 @@ std::shared_ptr<Entity> IndirectEntityDamageSource::getEntity() {
// }
std::shared_ptr<ChatPacket> IndirectEntityDamageSource::getDeathMessagePacket(
std::shared_ptr<Player> player) {
std::shared_ptr<LivingEntity> player) {
std::shared_ptr<ItemInstance> held =
entity->instanceof(eTYPE_LIVINGENTITY)
? std::dynamic_pointer_cast<LivingEntity>(entity)->getCarriedItem()
: nullptr;
std::wstring additional = L"";
int type;
if (owner != NULL) {
@ -45,6 +50,17 @@ std::shared_ptr<ChatPacket> IndirectEntityDamageSource::getDeathMessagePacket(
} else {
type = entity->GetType();
}
return std::shared_ptr<ChatPacket>(
new ChatPacket(player->name, m_msgId, type, additional));
if (held != NULL && held->hasCustomHoverName()) {
return std::shared_ptr<ChatPacket>(
new ChatPacket(player->getNetworkName(), m_msgWithItemId, type,
additional, held->getHoverName()));
} else {
return std::shared_ptr<ChatPacket>(new ChatPacket(
player->getNetworkName(), m_msgId, type, additional));
}
}
// 4J: Copy function
DamageSource* IndirectEntityDamageSource::copy() {
return new IndirectEntityDamageSource(*this);
}

View file

@ -13,6 +13,7 @@ public:
// IndirectEntityDamageSource(const std::wstring &msgId,
// std::shared_ptr<Entity> entity, std::shared_ptr<Entity> owner);
IndirectEntityDamageSource(ChatPacket::EChatPacketMessage msgId,
ChatPacket::EChatPacketMessage msgWithItemId,
std::shared_ptr<Entity> entity,
std::shared_ptr<Entity> owner);
virtual ~IndirectEntityDamageSource() {}
@ -25,5 +26,7 @@ public:
// virtual std::wstring getLocalizedDeathMessage(std::shared_ptr<Player>
// player);
virtual std::shared_ptr<ChatPacket> getDeathMessagePacket(
std::shared_ptr<Player> player);
std::shared_ptr<LivingEntity> player);
virtual DamageSource* copy();
};

View file

@ -83,8 +83,8 @@ void ItemEntity::tick() {
xd = (random->nextFloat() - random->nextFloat()) * 0.2f;
zd = (random->nextFloat() - random->nextFloat()) * 0.2f;
MemSect(31);
level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.4f,
2.0f + random->nextFloat() * 0.4f);
playSound(eSoundType_RANDOM_FIZZ, 0.4f,
2.0f + random->nextFloat() * 0.4f);
MemSect(0);
}
@ -168,7 +168,7 @@ bool ItemEntity::updateInWaterState() {
void ItemEntity::burn(int dmg) { hurt(DamageSource::inFire, dmg); }
bool ItemEntity::hurt(DamageSource* source, int damage) {
bool ItemEntity::hurt(DamageSource* source, float damage) {
// 4J - added next line: found whilst debugging an issue with item entities
// getting into a bad state when being created by a cactus, since entities
// insides cactuses get hurt and therefore depending on the timing of things
@ -177,6 +177,10 @@ bool ItemEntity::hurt(DamageSource* source, int damage) {
// hurt?
if (level->isClientSide) return false;
if (isInvulnerable()) return false;
if (getItem() != NULL && getItem()->id == Item::netherStar_Id &&
source->isExplosion())
return false;
markHurt();
health -= damage;
if (health <= 0) {
@ -238,8 +242,8 @@ void ItemEntity::playerTouch(std::shared_ptr<Player> player) {
player->awardStat(GenericStats::blazeRod(),
GenericStats::param_blazeRod());
level->playSound(
shared_from_this(), eSoundType_RANDOM_POP, 0.2f,
playSound(
eSoundType_RANDOM_POP, 0.2f,
((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f);
player->take(shared_from_this(), orgCount);
// System.out.println(item.count + ", " + orgCount);
@ -252,6 +256,12 @@ std::wstring ItemEntity::getAName() {
// return I18n.get("item." + item.getDescriptionId());
}
void ItemEntity::changeDimension(int i) {
Entity::changeDimension(i);
if (!level->isClientSide) mergeWithNeighbours();
}
std::shared_ptr<ItemInstance> ItemEntity::getItem() {
std::shared_ptr<ItemInstance> result =
getEntityData()->getItemInstance(DATA_ITEM);
@ -262,7 +272,7 @@ std::shared_ptr<ItemInstance> ItemEntity::getItem() {
// level.getLogger().severe("Item entity " + entityId + " has no
// item?!");
}
return std::shared_ptr<ItemInstance>(new ItemInstance(Tile::rock));
return std::shared_ptr<ItemInstance>(new ItemInstance(Tile::stone));
}
return result;

View file

@ -59,13 +59,13 @@ protected:
virtual void burn(int dmg);
public:
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
virtual void addAdditonalSaveData(CompoundTag* entityTag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void playerTouch(std::shared_ptr<Player> player);
virtual std::wstring getAName();
virtual void changeDimension(int i);
std::shared_ptr<ItemInstance> getItem();
void setItem(std::shared_ptr<ItemInstance> item);
virtual bool isAttackable();

View file

@ -0,0 +1,47 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.phys.h"
#include "LargeFireball.h"
LargeFireball::LargeFireball(Level* level) : Fireball(level) {
explosionPower = 1;
}
LargeFireball::LargeFireball(Level* level, double x, double y, double z,
double xa, double ya, double za)
: Fireball(level, x, y, z, xa, ya, za) {
explosionPower = 1;
}
LargeFireball::LargeFireball(Level* level, std::shared_ptr<LivingEntity> mob,
double xa, double ya, double za)
: Fireball(level, mob, xa, ya, za) {
explosionPower = 1;
}
void LargeFireball::onHit(HitResult* res) {
if (!level->isClientSide) {
if (res->entity != NULL) {
DamageSource* damageSource = DamageSource::fireball(
std::dynamic_pointer_cast<Fireball>(shared_from_this()), owner);
res->entity->hurt(damageSource, 6);
delete damageSource;
}
level->explode(
nullptr, x, y, z, explosionPower, true,
level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING));
remove();
}
}
void LargeFireball::addAdditonalSaveData(CompoundTag* tag) {
Fireball::addAdditonalSaveData(tag);
tag->putInt(L"ExplosionPower", explosionPower);
}
void LargeFireball::readAdditionalSaveData(CompoundTag* tag) {
Fireball::readAdditionalSaveData(tag);
if (tag->contains(L"ExplosionPower"))
explosionPower = tag->getInt(L"ExplosionPower");
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "Mobs/Fireball.h"
class LargeFireball : public Fireball {
public:
eINSTANCEOF GetType() { return eTYPE_LARGE_FIREBALL; }
static Entity* create(Level* level) { return new LargeFireball(level); }
public:
int explosionPower;
LargeFireball(Level* level);
LargeFireball(Level* level, double x, double y, double z, double xa,
double ya, double za);
LargeFireball(Level* level, std::shared_ptr<LivingEntity> mob, double xa,
double ya, double za);
protected:
void onHit(HitResult* res);
public:
void addAdditonalSaveData(CompoundTag* tag);
void readAdditionalSaveData(CompoundTag* tag);
};

View file

@ -0,0 +1,140 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.player.h"
#include "../Headers/net.minecraft.world.item.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.phys.h"
#include "LeashFenceKnotEntity.h"
void LeashFenceKnotEntity::_init() { defineSynchedData(); }
LeashFenceKnotEntity::LeashFenceKnotEntity(Level* level)
: HangingEntity(level) {
_init();
}
LeashFenceKnotEntity::LeashFenceKnotEntity(Level* level, int xTile, int yTile,
int zTile)
: HangingEntity(level, xTile, yTile, zTile, 0) {
_init();
setPos(xTile + .5, yTile + .5, zTile + .5);
}
void LeashFenceKnotEntity::defineSynchedData() {
HangingEntity::defineSynchedData();
}
void LeashFenceKnotEntity::setDir(int dir) {
// override to do nothing, knots don't have directions
}
int LeashFenceKnotEntity::getWidth() { return 9; }
int LeashFenceKnotEntity::getHeight() { return 9; }
bool LeashFenceKnotEntity::shouldRenderAtSqrDistance(double distance) {
return distance < 32 * 32;
}
void LeashFenceKnotEntity::dropItem(std::shared_ptr<Entity> causedBy) {}
bool LeashFenceKnotEntity::save(CompoundTag* entityTag) {
// knots are not saved, they are recreated by the entities that are tied
return false;
}
void LeashFenceKnotEntity::addAdditonalSaveData(CompoundTag* tag) {}
void LeashFenceKnotEntity::readAdditionalSaveData(CompoundTag* tag) {}
bool LeashFenceKnotEntity::interact(std::shared_ptr<Player> player) {
std::shared_ptr<ItemInstance> item = player->getCarriedItem();
bool attachedMob = false;
if (item != NULL && item->id == Item::lead_Id) {
if (!level->isClientSide) {
// look for entities that can be attached to the fence
double range = 7;
std::vector<std::shared_ptr<Entity> >* mobs =
level->getEntitiesOfClass(
typeid(Mob),
AABB::newTemp(x - range, y - range, z - range, x + range,
y + range, z + range));
if (mobs != NULL) {
for (AUTO_VAR(it, mobs->begin()); it != mobs->end(); ++it) {
std::shared_ptr<Mob> mob =
std::dynamic_pointer_cast<Mob>(*it);
if (mob->isLeashed() && mob->getLeashHolder() == player) {
mob->setLeashedTo(shared_from_this(), true);
attachedMob = true;
}
}
delete mobs;
}
}
}
if (!level->isClientSide && !attachedMob) {
remove();
if (player->abilities.instabuild) {
// if the player is in creative mode, attempt to remove all leashed
// mobs without dropping additional items
double range = 7;
std::vector<std::shared_ptr<Entity> >* mobs =
level->getEntitiesOfClass(
typeid(Mob),
AABB::newTemp(x - range, y - range, z - range, x + range,
y + range, z + range));
if (mobs != NULL) {
for (AUTO_VAR(it, mobs->begin()); it != mobs->end(); ++it) {
std::shared_ptr<Mob> mob =
std::dynamic_pointer_cast<Mob>(*it);
if (mob->isLeashed() &&
mob->getLeashHolder() == shared_from_this()) {
mob->dropLeash(true, false);
}
}
delete mobs;
}
}
}
return true;
}
bool LeashFenceKnotEntity::survives() {
// knots are placed on top of fence tiles
int tile = level->getTile(xTile, yTile, zTile);
if (Tile::tiles[tile] != NULL &&
Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_FENCE) {
return true;
}
return false;
}
std::shared_ptr<LeashFenceKnotEntity> LeashFenceKnotEntity::createAndAddKnot(
Level* level, int x, int y, int z) {
std::shared_ptr<LeashFenceKnotEntity> knot =
std::shared_ptr<LeashFenceKnotEntity>(
new LeashFenceKnotEntity(level, x, y, z));
knot->forcedLoading = true;
level->addEntity(knot);
return knot;
}
std::shared_ptr<LeashFenceKnotEntity> LeashFenceKnotEntity::findKnotAt(
Level* level, int x, int y, int z) {
std::vector<std::shared_ptr<Entity> >* knots = level->getEntitiesOfClass(
typeid(LeashFenceKnotEntity),
AABB::newTemp(x - 1.0, y - 1.0, z - 1.0, x + 1.0, y + 1.0, z + 1.0));
if (knots != NULL) {
for (AUTO_VAR(it, knots->begin()); it != knots->end(); ++it) {
std::shared_ptr<LeashFenceKnotEntity> knot =
std::dynamic_pointer_cast<LeashFenceKnotEntity>(*it);
if (knot->xTile == x && knot->yTile == y && knot->zTile == z) {
delete knots;
return knot;
}
}
delete knots;
}
return nullptr;
}

View file

@ -0,0 +1,38 @@
#pragma once
#include "HangingEntity.h"
class LeashFenceKnotEntity : public HangingEntity {
public:
eINSTANCEOF GetType() { return eTYPE_LEASHFENCEKNOT; };
static Entity* create(Level* level) {
return new LeashFenceKnotEntity(level);
}
private:
void _init();
public:
LeashFenceKnotEntity(Level* level);
LeashFenceKnotEntity(Level* level, int xTile, int yTile, int zTile);
protected:
void defineSynchedData();
public:
void setDir(int dir);
int getWidth();
int getHeight();
bool shouldRenderAtSqrDistance(double distance);
void dropItem(std::shared_ptr<Entity> causedBy);
bool save(CompoundTag* entityTag);
void addAdditonalSaveData(CompoundTag* tag);
void readAdditionalSaveData(CompoundTag* tag);
bool interact(std::shared_ptr<Player> player);
virtual bool survives();
static std::shared_ptr<LeashFenceKnotEntity> createAndAddKnot(Level* level,
int x, int y,
int z);
static std::shared_ptr<LeashFenceKnotEntity> findKnotAt(Level* level, int x,
int y, int z);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,330 @@
#pragma once
#include "Entity.h"
#include "MobType.h"
#include "../AI/Goals/GoalSelector.h"
#include "../Util/SharedConstants.h"
class CombatTracker;
class AttributeInstance;
class AttributeModifier;
class MobEffectInstance;
class BaseAttributeMap;
class Team;
class Attribute;
class MobEffect;
class HitResult;
class Vec3;
class LivingEntity : public Entity {
friend class MobSpawner;
protected:
// 4J - added for common ctor code
void _init();
public:
// 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts
eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY; }
static Entity* create(Level* level) { return NULL; }
private:
static AttributeModifier* SPEED_MODIFIER_SPRINTING;
public:
static const int SLOT_WEAPON = 0;
static const int SLOT_BOOTS = 1;
static const int SLOT_LEGGINGS = 2;
static const int SLOT_CHEST = 3;
static const int SLOT_HELM = 4;
static const int SWING_DURATION = 6;
static const int PLAYER_HURT_EXPERIENCE_TIME =
SharedConstants::TICKS_PER_SECOND * 5;
private:
static const double MIN_MOVEMENT_DISTANCE;
public:
static const int DATA_HEALTH_ID = 6;
static const int DATA_EFFECT_COLOR_ID = 7;
static const int DATA_EFFECT_AMBIENCE_ID = 8;
static const int DATA_ARROW_COUNT_ID = 9;
private:
BaseAttributeMap* attributes;
CombatTracker* combatTracker;
std::unordered_map<int, MobEffectInstance*> activeEffects;
ItemInstanceArray lastEquipment;
public:
bool swinging;
int swingTime;
int removeArrowTime;
float lastHealth;
int hurtTime;
int hurtDuration;
float hurtDir;
int deathTime;
int attackTime;
float oAttackAnim, attackAnim;
float walkAnimSpeedO;
float walkAnimSpeed;
float walkAnimPos;
int invulnerableDuration;
float oTilt, tilt;
float timeOffs;
float rotA;
float yBodyRot, yBodyRotO;
float yHeadRot, yHeadRotO;
float flyingSpeed;
protected:
std::shared_ptr<Player> lastHurtByPlayer;
int lastHurtByPlayerTime;
bool dead;
int noActionTime;
float oRun, run;
float animStep, animStepO;
float rotOffs;
int deathScore;
float lastHurt;
bool jumping;
public:
float xxa;
float yya;
protected:
float yRotA;
int lSteps;
double lx, ly, lz, lyr, lxr;
private:
bool effectsDirty;
std::shared_ptr<LivingEntity> lastHurtByMob;
int lastHurtByMobTimestamp;
std::shared_ptr<LivingEntity> lastHurtMob;
int lastHurtMobTimestamp;
float speed;
protected:
int noJumpDelay;
private:
float absorptionAmount;
public:
LivingEntity(Level* level);
virtual ~LivingEntity();
protected:
virtual void defineSynchedData();
virtual void registerAttributes();
virtual void checkFallDamage(double ya, bool onGround);
public:
virtual bool isWaterMob();
virtual void baseTick();
virtual bool isBaby();
protected:
virtual void tickDeath();
virtual int decreaseAirSupply(int currentSupply);
virtual int getExperienceReward(std::shared_ptr<Player> killedBy);
virtual bool isAlwaysExperienceDropper();
public:
virtual Random* getRandom();
virtual std::shared_ptr<LivingEntity> getLastHurtByMob();
virtual int getLastHurtByMobTimestamp();
virtual void setLastHurtByMob(std::shared_ptr<LivingEntity> hurtBy);
virtual std::shared_ptr<LivingEntity> getLastHurtMob();
virtual int getLastHurtMobTimestamp();
virtual void setLastHurtMob(std::shared_ptr<Entity> target);
virtual int getNoActionTime();
virtual void addAdditonalSaveData(CompoundTag* entityTag);
virtual void readAdditionalSaveData(CompoundTag* tag);
protected:
virtual void tickEffects();
public:
virtual void removeAllEffects();
virtual std::vector<MobEffectInstance*>* getActiveEffects();
virtual bool hasEffect(int id);
virtual bool hasEffect(MobEffect* effect);
virtual MobEffectInstance* getEffect(MobEffect* effect);
virtual void addEffect(MobEffectInstance* newEffect);
virtual void addEffectNoUpdate(MobEffectInstance* newEffect); // 4J added
virtual bool canBeAffected(MobEffectInstance* newEffect);
virtual bool isInvertedHealAndHarm();
virtual void removeEffectNoUpdate(int effectId);
virtual void removeEffect(int effectId);
protected:
virtual void onEffectAdded(MobEffectInstance* effect);
virtual void onEffectUpdated(MobEffectInstance* effect,
bool doRefreshAttributes);
virtual void onEffectRemoved(MobEffectInstance* effect);
public:
virtual void heal(float heal);
virtual float getHealth();
virtual void setHealth(float health);
virtual bool hurt(DamageSource* source, float dmg);
virtual void breakItem(std::shared_ptr<ItemInstance> itemInstance);
virtual void die(DamageSource* source);
protected:
virtual void dropEquipment(bool byPlayer, int playerBonusLevel);
public:
virtual void knockback(std::shared_ptr<Entity> source, float dmg, double xd,
double zd);
protected:
virtual int getHurtSound();
virtual int getDeathSound();
protected:
virtual void dropRareDeathLoot(int rareLootLevel);
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
public:
virtual bool onLadder();
virtual bool isShootable();
virtual bool isAlive();
virtual void causeFallDamage(float distance);
virtual void animateHurt();
virtual int getArmorValue();
protected:
virtual void hurtArmor(float damage);
virtual float getDamageAfterArmorAbsorb(DamageSource* damageSource,
float damage);
virtual float getDamageAfterMagicAbsorb(DamageSource* damageSource,
float damage);
virtual void actuallyHurt(DamageSource* source, float dmg);
public:
virtual CombatTracker* getCombatTracker();
virtual std::shared_ptr<LivingEntity> getKillCredit();
virtual float getMaxHealth();
virtual int getArrowCount();
virtual void setArrowCount(int count);
private:
int getCurrentSwingDuration();
public:
virtual void swing();
virtual void handleEntityEvent(uint8_t id);
protected:
virtual void outOfWorld();
virtual void updateSwingTime();
public:
virtual AttributeInstance* getAttribute(Attribute* attribute);
virtual BaseAttributeMap* getAttributes();
virtual MobType getMobType();
virtual std::shared_ptr<ItemInstance> getCarriedItem() = 0;
virtual std::shared_ptr<ItemInstance> getCarried(int slot) = 0;
virtual std::shared_ptr<ItemInstance> getArmor(int pos) = 0;
virtual void setEquippedSlot(int slot,
std::shared_ptr<ItemInstance> item) = 0;
virtual void setSprinting(bool value);
virtual ItemInstanceArray getEquipmentSlots() = 0;
virtual Icon* getItemInHandIcon(std::shared_ptr<ItemInstance> item,
int layer);
protected:
virtual float getSoundVolume();
virtual float getVoicePitch();
virtual bool isImmobile();
public:
virtual void teleportTo(double x, double y, double z);
protected:
virtual void findStandUpPosition(std::shared_ptr<Entity> vehicle);
public:
virtual bool shouldShowName();
protected:
virtual void jumpFromGround();
public:
virtual void travel(float xa, float ya);
virtual int getLightColor(float a); // 4J - added
protected:
virtual bool useNewAi();
public:
virtual float getSpeed();
virtual void setSpeed(float speed);
virtual bool doHurtTarget(std::shared_ptr<Entity> target);
virtual bool isSleeping();
virtual void tick();
protected:
virtual float tickHeadTurn(float yBodyRotT, float walkSpeed);
public:
virtual void aiStep();
protected:
virtual void newServerAiStep();
virtual void pushEntities();
virtual void doPush(std::shared_ptr<Entity> e);
public:
virtual void rideTick();
virtual void lerpTo(double x, double y, double z, float yRot, float xRot,
int steps);
protected:
virtual void serverAiMobStep();
virtual void serverAiStep();
public:
virtual void setJumping(bool jump);
virtual void take(std::shared_ptr<Entity> e, int orgCount);
virtual bool canSee(std::shared_ptr<Entity> target);
public:
virtual Vec3* getLookAngle();
virtual Vec3* getViewVector(float a);
virtual float getAttackAnim(float a);
virtual Vec3* getPos(float a);
virtual HitResult* pick(double range, float a);
virtual bool isEffectiveAi();
virtual bool isPickable();
virtual bool isPushable();
virtual float getHeadHeight();
protected:
virtual void markHurt();
public:
virtual float getYHeadRot();
virtual void setYHeadRot(float yHeadRot);
virtual float getAbsorptionAmount();
virtual void setAbsorptionAmount(float absorptionAmount);
virtual Team* getTeam();
virtual bool isAlliedTo(std::shared_ptr<LivingEntity> other);
virtual bool isAlliedTo(Team* other);
};

View file

@ -0,0 +1,36 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.network.packet.h"
#include "MinecartChest.h"
MinecartChest::MinecartChest(Level* level) : MinecartContainer(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
MinecartChest::MinecartChest(Level* level, double x, double y, double z)
: MinecartContainer(level, x, y, z) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
// 4J Added
int MinecartChest::getContainerType() {
return ContainerOpenPacket::MINECART_CHEST;
}
void MinecartChest::destroy(DamageSource* source) {
MinecartContainer::destroy(source);
spawnAtLocation(Tile::chest_Id, 1, 0);
}
unsigned int MinecartChest::getContainerSize() { return 9 * 3; }
int MinecartChest::getType() { return TYPE_CHEST; }
Tile* MinecartChest::getDefaultDisplayTile() { return Tile::chest; }
int MinecartChest::getDefaultDisplayOffset() { return 8; }

View file

@ -0,0 +1,22 @@
#pragma once
#include "MinecartContainer.h"
class MinecartChest : public MinecartContainer {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_CHEST; };
static Entity* create(Level* level) { return new MinecartChest(level); }
public:
MinecartChest(Level* level);
MinecartChest(Level* level, double x, double y, double z);
// 4J added
virtual int getContainerType();
virtual void destroy(DamageSource* source);
virtual unsigned int getContainerSize();
virtual int getType();
virtual Tile* getDefaultDisplayTile();
virtual int getDefaultDisplayOffset();
};

View file

@ -0,0 +1,213 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.item.h"
#include "../Headers/net.minecraft.world.item.h"
#include "../Headers/net.minecraft.world.inventory.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.redstone.h"
#include "MinecartContainer.h"
void MinecartContainer::_init() {
items = ItemInstanceArray(9 * 4);
dropEquipment = true;
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
MinecartContainer::MinecartContainer(Level* level) : Minecart(level) {
_init();
}
MinecartContainer::MinecartContainer(Level* level, double x, double y, double z)
: Minecart(level, x, y, z) {
_init();
}
void MinecartContainer::destroy(DamageSource* source) {
Minecart::destroy(source);
for (int i = 0; i < getContainerSize(); i++) {
std::shared_ptr<ItemInstance> item = getItem(i);
if (item != NULL) {
float xo = random->nextFloat() * 0.8f + 0.1f;
float yo = random->nextFloat() * 0.8f + 0.1f;
float zo = random->nextFloat() * 0.8f + 0.1f;
while (item->count > 0) {
int count = random->nextInt(21) + 10;
if (count > item->count) count = item->count;
item->count -= count;
std::shared_ptr<ItemEntity> itemEntity =
std::shared_ptr<ItemEntity>(new ItemEntity(
level, x + xo, y + yo, z + zo,
std::shared_ptr<ItemInstance>(new ItemInstance(
item->id, count, item->getAuxValue()))));
float pow = 0.05f;
itemEntity->xd = (float)random->nextGaussian() * pow;
itemEntity->yd = (float)random->nextGaussian() * pow + 0.2f;
itemEntity->zd = (float)random->nextGaussian() * pow;
level->addEntity(itemEntity);
}
}
}
}
std::shared_ptr<ItemInstance> MinecartContainer::getItem(unsigned int slot) {
return items[slot];
}
std::shared_ptr<ItemInstance> MinecartContainer::removeItem(unsigned int slot,
int count) {
if (items[slot] != NULL) {
if (items[slot]->count <= count) {
std::shared_ptr<ItemInstance> item = items[slot];
items[slot] = nullptr;
return item;
} else {
std::shared_ptr<ItemInstance> i = items[slot]->remove(count);
if (items[slot]->count == 0) items[slot] = nullptr;
return i;
}
}
return nullptr;
}
std::shared_ptr<ItemInstance> MinecartContainer::removeItemNoUpdate(int slot) {
if (items[slot] != NULL) {
std::shared_ptr<ItemInstance> item = items[slot];
items[slot] = nullptr;
return item;
}
return nullptr;
}
void MinecartContainer::setItem(unsigned int slot,
std::shared_ptr<ItemInstance> item) {
items[slot] = item;
if (item != NULL && item->count > getMaxStackSize())
item->count = getMaxStackSize();
}
void MinecartContainer::setChanged() {}
bool MinecartContainer::stillValid(std::shared_ptr<Player> player) {
if (removed) return false;
if (player->distanceToSqr(shared_from_this()) > 8 * 8) return false;
return true;
}
void MinecartContainer::startOpen() {}
void MinecartContainer::stopOpen() {}
bool MinecartContainer::canPlaceItem(int slot,
std::shared_ptr<ItemInstance> item) {
return true;
}
std::wstring MinecartContainer::getName() {
return hasCustomName() ? getCustomName()
: app.GetString(IDS_CONTAINER_MINECART);
}
int MinecartContainer::getMaxStackSize() {
return Container::LARGE_MAX_STACK_SIZE;
}
void MinecartContainer::changeDimension(int i) {
dropEquipment = false;
Minecart::changeDimension(i);
}
void MinecartContainer::remove() {
if (dropEquipment) {
for (int i = 0; i < getContainerSize(); i++) {
std::shared_ptr<ItemInstance> item = getItem(i);
if (item != NULL) {
float xo = random->nextFloat() * 0.8f + 0.1f;
float yo = random->nextFloat() * 0.8f + 0.1f;
float zo = random->nextFloat() * 0.8f + 0.1f;
while (item->count > 0) {
int count = random->nextInt(21) + 10;
if (count > item->count) count = item->count;
item->count -= count;
std::shared_ptr<ItemEntity> itemEntity =
std::shared_ptr<ItemEntity>(new ItemEntity(
level, x + xo, y + yo, z + zo,
std::shared_ptr<ItemInstance>(new ItemInstance(
item->id, count, item->getAuxValue()))));
if (item->hasTag()) {
itemEntity->getItem()->setTag(
(CompoundTag*)item->getTag()->copy());
}
float pow = 0.05f;
itemEntity->xd = (float)random->nextGaussian() * pow;
itemEntity->yd = (float)random->nextGaussian() * pow + 0.2f;
itemEntity->zd = (float)random->nextGaussian() * pow;
level->addEntity(itemEntity);
}
}
}
}
Minecart::remove();
}
void MinecartContainer::addAdditonalSaveData(CompoundTag* base) {
Minecart::addAdditonalSaveData(base);
ListTag<CompoundTag>* listTag = new ListTag<CompoundTag>();
for (int i = 0; i < items.length; i++) {
if (items[i] != NULL) {
CompoundTag* tag = new CompoundTag();
tag->putByte(L"Slot", (uint8_t)i);
items[i]->save(tag);
listTag->add(tag);
}
}
base->put(L"Items", listTag);
}
void MinecartContainer::readAdditionalSaveData(CompoundTag* base) {
Minecart::readAdditionalSaveData(base);
ListTag<CompoundTag>* inventoryList =
(ListTag<CompoundTag>*)base->getList(L"Items");
delete[] items.data;
items = ItemInstanceArray(getContainerSize());
for (int i = 0; i < inventoryList->size(); i++) {
CompoundTag* tag = inventoryList->get(i);
int slot = tag->getByte(L"Slot") & 0xff;
if (slot >= 0 && slot < items.length)
items[slot] = ItemInstance::fromTag(tag);
}
}
bool MinecartContainer::interact(std::shared_ptr<Player> player) {
if (!level->isClientSide) {
player->openContainer(
std::dynamic_pointer_cast<Container>(shared_from_this()));
}
return true;
}
void MinecartContainer::applyNaturalSlowdown() {
std::shared_ptr<Container> container =
std::dynamic_pointer_cast<Container>(shared_from_this());
int emptiness =
Redstone::SIGNAL_MAX -
AbstractContainerMenu::getRedstoneSignalFromContainer(container);
float keep = 0.98f + (emptiness * 0.001f);
xd *= keep;
yd *= 0;
zd *= keep;
}

View file

@ -0,0 +1,47 @@
#pragma once
#include "Mobs/Minecart.h"
#include "../Containers/Container.h"
class MinecartContainer : public Minecart, public virtual Container {
private:
ItemInstanceArray items;
bool dropEquipment;
void _init();
public:
MinecartContainer(Level* level);
MinecartContainer(Level* level, double x, double y, double z);
virtual void destroy(DamageSource* source);
virtual std::shared_ptr<ItemInstance> getItem(unsigned int slot);
virtual std::shared_ptr<ItemInstance> removeItem(unsigned int slot,
int count);
virtual std::shared_ptr<ItemInstance> removeItemNoUpdate(int slot);
virtual void setItem(unsigned int slot, std::shared_ptr<ItemInstance> item);
virtual void setChanged();
virtual bool stillValid(std::shared_ptr<Player> player);
virtual void startOpen();
virtual void stopOpen();
virtual bool canPlaceItem(int slot, std::shared_ptr<ItemInstance> item);
virtual std::wstring getName();
virtual int getMaxStackSize();
virtual void changeDimension(int i);
virtual void remove();
protected:
virtual void addAdditonalSaveData(CompoundTag* base);
virtual void readAdditionalSaveData(CompoundTag* base);
public:
virtual bool interact(std::shared_ptr<Player> player);
protected:
virtual void applyNaturalSlowdown();
public:
// 4J Stu - For container
virtual bool hasCustomName() { return Minecart::hasCustomName(); }
virtual std::wstring getCustomName() { return Minecart::getCustomName(); }
};

View file

@ -0,0 +1,148 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.entity.player.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.item.h"
#include "../Headers/net.minecraft.network.packet.h"
#include "MinecartFurnace.h"
MinecartFurnace::MinecartFurnace(Level* level) : Minecart(level) {
defineSynchedData();
fuel = 0;
xPush = zPush = 0.0f;
}
MinecartFurnace::MinecartFurnace(Level* level, double x, double y, double z)
: Minecart(level, x, y, z) {
defineSynchedData();
fuel = 0;
xPush = zPush = 0.0f;
}
// 4J Added
int MinecartFurnace::getContainerType() {
return ContainerOpenPacket::MINECART_HOPPER;
}
int MinecartFurnace::getType() { return TYPE_FURNACE; }
void MinecartFurnace::defineSynchedData() {
Minecart::defineSynchedData();
entityData->define(DATA_ID_FUEL, (uint8_t)0);
}
void MinecartFurnace::tick() {
Minecart::tick();
if (fuel > 0) {
fuel--;
}
if (fuel <= 0) {
xPush = zPush = 0;
}
setHasFuel(fuel > 0);
if (hasFuel() && random->nextInt(4) == 0) {
level->addParticle(eParticleType_largesmoke, x, y + 0.8, z, 0, 0, 0);
}
}
void MinecartFurnace::destroy(DamageSource* source) {
Minecart::destroy(source);
if (!source->isExplosion()) {
spawnAtLocation(
std::shared_ptr<ItemInstance>(new ItemInstance(Tile::furnace, 1)),
0);
}
}
void MinecartFurnace::moveAlongTrack(int xt, int yt, int zt, double maxSpeed,
double slideSpeed, int tile, int data) {
Minecart::moveAlongTrack(xt, yt, zt, maxSpeed, slideSpeed, tile, data);
double sd = xPush * xPush + zPush * zPush;
if (sd > 0.01 * 0.01 && xd * xd + zd * zd > 0.001) {
sd = Mth::sqrt(sd);
xPush /= sd;
zPush /= sd;
if (xPush * xd + zPush * zd < 0) {
xPush = 0;
zPush = 0;
} else {
xPush = xd;
zPush = zd;
}
}
}
void MinecartFurnace::applyNaturalSlowdown() {
double sd = xPush * xPush + zPush * zPush;
if (sd > 0.01 * 0.01) {
sd = Mth::sqrt(sd);
xPush /= sd;
zPush /= sd;
double speed = 0.05;
xd *= 0.8f;
yd *= 0;
zd *= 0.8f;
xd += xPush * speed;
zd += zPush * speed;
} else {
xd *= 0.98f;
yd *= 0;
zd *= 0.98f;
}
Minecart::applyNaturalSlowdown();
}
bool MinecartFurnace::interact(std::shared_ptr<Player> player) {
std::shared_ptr<ItemInstance> selected = player->inventory->getSelected();
if (selected != NULL && selected->id == Item::coal_Id) {
if (!player->abilities.instabuild && --selected->count == 0)
player->inventory->setItem(player->inventory->selected, nullptr);
fuel += SharedConstants::TICKS_PER_SECOND * 180;
}
xPush = x - player->x;
zPush = z - player->z;
return true;
}
void MinecartFurnace::addAdditonalSaveData(CompoundTag* base) {
Minecart::addAdditonalSaveData(base);
base->putDouble(L"PushX", xPush);
base->putDouble(L"PushZ", zPush);
base->putShort(L"Fuel", (short)fuel);
}
void MinecartFurnace::readAdditionalSaveData(CompoundTag* base) {
Minecart::readAdditionalSaveData(base);
xPush = base->getDouble(L"PushX");
zPush = base->getDouble(L"PushZ");
fuel = base->getShort(L"Fuel");
}
bool MinecartFurnace::hasFuel() {
return (entityData->getByte(DATA_ID_FUEL) & 1) != 0;
}
void MinecartFurnace::setHasFuel(bool fuel) {
if (fuel) {
entityData->set(DATA_ID_FUEL,
(uint8_t)(entityData->getByte(DATA_ID_FUEL) | 1));
} else {
entityData->set(DATA_ID_FUEL,
(uint8_t)(entityData->getByte(DATA_ID_FUEL) & ~1));
}
}
Tile* MinecartFurnace::getDefaultDisplayTile() { return Tile::furnace_lit; }
int MinecartFurnace::getDefaultDisplayData() { return 2; }

View file

@ -0,0 +1,51 @@
#pragma once
#include "Mobs/Minecart.h"
class MinecartFurnace : public Minecart {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_FURNACE; };
static Entity* create(Level* level) { return new MinecartFurnace(level); }
private:
static const int DATA_ID_FUEL = 16;
private:
int fuel;
public:
double xPush, zPush;
MinecartFurnace(Level* level);
MinecartFurnace(Level* level, double x, double y, double z);
// 4J added
virtual int getContainerType();
int getType();
protected:
void defineSynchedData();
public:
void tick();
void destroy(DamageSource* source);
protected:
void moveAlongTrack(int xt, int yt, int zt, double maxSpeed,
double slideSpeed, int tile, int data);
void applyNaturalSlowdown();
public:
bool interact(std::shared_ptr<Player> player);
protected:
void addAdditonalSaveData(CompoundTag* base);
void readAdditionalSaveData(CompoundTag* base);
bool hasFuel();
void setHasFuel(bool fuel);
public:
Tile* getDefaultDisplayTile();
int getDefaultDisplayData();
};

View file

@ -0,0 +1,119 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.entity.player.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "../Headers/net.minecraft.world.level.tile.entity.h"
#include "../Headers/net.minecraft.world.entity.item.h"
#include "../Headers/net.minecraft.world.phys.h"
#include "MinecartHopper.h"
const int MinecartHopper::MOVE_ITEM_SPEED =
HopperTileEntity::MOVE_ITEM_SPEED / 2;
void MinecartHopper::_init() {
enabled = true;
cooldownTime = -1;
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
MinecartHopper::MinecartHopper(Level* level) : MinecartContainer(level) {
_init();
}
MinecartHopper::MinecartHopper(Level* level, double x, double y, double z)
: MinecartContainer(level, x, y, z) {
_init();
}
int MinecartHopper::getType() { return TYPE_HOPPER; }
Tile* MinecartHopper::getDefaultDisplayTile() { return Tile::hopper; }
int MinecartHopper::getDefaultDisplayOffset() { return 1; }
unsigned int MinecartHopper::getContainerSize() { return 5; }
bool MinecartHopper::interact(std::shared_ptr<Player> player) {
if (!level->isClientSide) {
player->openHopper(
std::dynamic_pointer_cast<MinecartHopper>(shared_from_this()));
}
return true;
}
void MinecartHopper::activateMinecart(int xt, int yt, int zt, bool state) {
bool newEnabled = !state;
if (newEnabled != isEnabled()) {
setEnabled(newEnabled);
}
}
bool MinecartHopper::isEnabled() { return enabled; }
void MinecartHopper::setEnabled(bool enabled) { this->enabled = enabled; }
Level* MinecartHopper::getLevel() { return level; }
double MinecartHopper::getLevelX() { return x; }
double MinecartHopper::getLevelY() { return y; }
double MinecartHopper::getLevelZ() { return z; }
void MinecartHopper::tick() {
MinecartContainer::tick();
if (!level->isClientSide && isAlive() && isEnabled()) {
cooldownTime--;
if (!isOnCooldown()) {
setCooldown(0);
if (suckInItems()) {
setCooldown(MOVE_ITEM_SPEED);
MinecartContainer::setChanged();
}
}
}
}
bool MinecartHopper::suckInItems() {
if (HopperTileEntity::suckInItems(this)) return true;
std::vector<std::shared_ptr<Entity> >* items =
level->getEntitiesOfClass(typeid(ItemEntity), bb->grow(0.25f, 0, 0.25f),
EntitySelector::ENTITY_STILL_ALIVE);
if (items->size() > 0) {
HopperTileEntity::addItem(
this, std::dynamic_pointer_cast<ItemEntity>(items->at(0)));
}
delete items;
return false;
}
void MinecartHopper::destroy(DamageSource* source) {
MinecartContainer::destroy(source);
spawnAtLocation(Tile::hopper_Id, 1, 0);
}
void MinecartHopper::addAdditonalSaveData(CompoundTag* base) {
MinecartContainer::addAdditonalSaveData(base);
base->putInt(L"TransferCooldown", cooldownTime);
}
void MinecartHopper::readAdditionalSaveData(CompoundTag* base) {
MinecartContainer::readAdditionalSaveData(base);
cooldownTime = base->getInt(L"TransferCooldown");
}
void MinecartHopper::setCooldown(int time) { cooldownTime = time; }
bool MinecartHopper::isOnCooldown() { return cooldownTime > 0; }

View file

@ -0,0 +1,81 @@
#pragma once
#include "MinecartContainer.h"
#include "../Blocks/TileEntities/Hopper.h"
class MinecartHopper : public MinecartContainer, public Hopper {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_HOPPER; };
static Entity* create(Level* level) { return new MinecartHopper(level); }
public:
static const int MOVE_ITEM_SPEED;
private:
bool enabled;
int cooldownTime;
void _init();
public:
MinecartHopper(Level* level);
MinecartHopper(Level* level, double x, double y, double z);
virtual int getType();
virtual Tile* getDefaultDisplayTile();
virtual int getDefaultDisplayOffset();
virtual unsigned int getContainerSize();
virtual bool interact(std::shared_ptr<Player> player);
virtual void activateMinecart(int xt, int yt, int zt, bool state);
virtual bool isEnabled();
virtual void setEnabled(bool enabled);
virtual Level* getLevel();
virtual double getLevelX();
virtual double getLevelY();
virtual double getLevelZ();
virtual void tick();
virtual bool suckInItems();
virtual void destroy(DamageSource* source);
protected:
virtual void addAdditonalSaveData(CompoundTag* base);
virtual void readAdditionalSaveData(CompoundTag* base);
public:
void setCooldown(int time);
bool isOnCooldown();
// 4J For Hopper
virtual std::shared_ptr<ItemInstance> getItem(unsigned int slot) {
return MinecartContainer::getItem(slot);
}
virtual std::shared_ptr<ItemInstance> removeItem(unsigned int slot,
int count) {
return MinecartContainer::removeItem(slot, count);
}
virtual std::shared_ptr<ItemInstance> removeItemNoUpdate(int slot) {
return MinecartContainer::removeItemNoUpdate(slot);
}
virtual void setItem(unsigned int slot,
std::shared_ptr<ItemInstance> item) {
MinecartContainer::setItem(slot, item);
}
virtual std::wstring getName() { return MinecartContainer::getName(); }
virtual std::wstring getCustomName() {
return MinecartContainer::getCustomName();
}
virtual bool hasCustomName() { return MinecartContainer::hasCustomName(); }
virtual int getMaxStackSize() {
return MinecartContainer::getMaxStackSize();
}
virtual void setChanged() { MinecartContainer::setChanged(); }
virtual bool stillValid(std::shared_ptr<Player> player) {
return MinecartContainer::stillValid(player);
}
virtual void startOpen() { MinecartContainer::startOpen(); }
virtual void stopOpen() { MinecartContainer::stopOpen(); }
virtual bool canPlaceItem(int slot, std::shared_ptr<ItemInstance> item) {
return MinecartContainer::canPlaceItem(slot, item);
}
};

View file

@ -0,0 +1,32 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.entity.player.h"
#include "../Headers/net.minecraft.world.level.h"
#include "MinecartRideable.h"
MinecartRideable::MinecartRideable(Level* level) : Minecart(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
MinecartRideable::MinecartRideable(Level* level, double x, double y, double z)
: Minecart(level, x, y, z) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
}
bool MinecartRideable::interact(std::shared_ptr<Player> player) {
if (rider.lock() != NULL && rider.lock()->instanceof(eTYPE_PLAYER) &&
rider.lock() != player)
return true;
if (rider.lock() != NULL && rider.lock() != player) return false;
if (!level->isClientSide) {
player->ride(shared_from_this());
}
return true;
}
int MinecartRideable::getType() { return TYPE_RIDEABLE; }

View file

@ -0,0 +1,16 @@
#pragma once
#include "Mobs/Minecart.h"
class MinecartRideable : public Minecart {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_RIDEABLE; };
static Entity* create(Level* level) { return new MinecartRideable(level); }
public:
MinecartRideable(Level* level);
MinecartRideable(Level* level, double x, double y, double z);
virtual bool interact(std::shared_ptr<Player> player);
virtual int getType();
};

View file

@ -0,0 +1,74 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "MinecartSpawner.h"
MinecartSpawner::MinecartMobSpawner::MinecartMobSpawner(
MinecartSpawner* parent) {
m_parent = parent;
}
void MinecartSpawner::MinecartMobSpawner::broadcastEvent(int id) {
m_parent->level->broadcastEntityEvent(m_parent->shared_from_this(),
(uint8_t)id);
}
Level* MinecartSpawner::MinecartMobSpawner::getLevel() {
return m_parent->level;
}
int MinecartSpawner::MinecartMobSpawner::getX() {
return Mth::floor(m_parent->x);
}
int MinecartSpawner::MinecartMobSpawner::getY() {
return Mth::floor(m_parent->y);
}
int MinecartSpawner::MinecartMobSpawner::getZ() {
return Mth::floor(m_parent->z);
}
MinecartSpawner::MinecartSpawner(Level* level) : Minecart(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
spawner = new MinecartMobSpawner(this);
}
MinecartSpawner::MinecartSpawner(Level* level, double x, double y, double z)
: Minecart(level, x, y, z) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
spawner = new MinecartMobSpawner(this);
}
MinecartSpawner::~MinecartSpawner() { delete spawner; }
int MinecartSpawner::getType() { return TYPE_SPAWNER; }
Tile* MinecartSpawner::getDefaultDisplayTile() { return Tile::mobSpawner; }
void MinecartSpawner::readAdditionalSaveData(CompoundTag* tag) {
Minecart::readAdditionalSaveData(tag);
spawner->load(tag);
}
void MinecartSpawner::addAdditonalSaveData(CompoundTag* tag) {
Minecart::addAdditonalSaveData(tag);
spawner->save(tag);
}
void MinecartSpawner::handleEntityEvent(uint8_t eventId) {
spawner->onEventTriggered(eventId);
}
void MinecartSpawner::tick() {
Minecart::tick();
spawner->tick();
}
BaseMobSpawner* MinecartSpawner::getSpawner() { return spawner; }

View file

@ -0,0 +1,43 @@
#pragma once
#include "Mobs/Minecart.h"
#include "../Level/BaseMobSpawner.h"
class MinecartSpawner : public Minecart {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_SPAWNER; };
static Entity* create(Level* level) { return new MinecartSpawner(level); }
private:
BaseMobSpawner* spawner;
class MinecartMobSpawner : public BaseMobSpawner {
private:
MinecartSpawner* m_parent;
public:
MinecartMobSpawner(MinecartSpawner* parent);
void broadcastEvent(int id);
Level* getLevel();
int getX();
int getY();
int getZ();
};
public:
MinecartSpawner(Level* level);
MinecartSpawner(Level* level, double x, double y, double z);
virtual ~MinecartSpawner();
virtual int getType();
virtual Tile* getDefaultDisplayTile();
protected:
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void addAdditonalSaveData(CompoundTag* tag);
public:
virtual void handleEntityEvent(uint8_t eventId);
virtual void tick();
virtual BaseMobSpawner* getSpawner();
};

View file

@ -0,0 +1,136 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.level.tile.h"
#include "MinecartTNT.h"
void MinecartTNT::_init() {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
fuse = -1;
}
MinecartTNT::MinecartTNT(Level* level) : Minecart(level) { _init(); }
MinecartTNT::MinecartTNT(Level* level, double x, double y, double z)
: Minecart(level, x, y, z) {
_init();
}
int MinecartTNT::getType() { return TYPE_TNT; }
Tile* MinecartTNT::getDefaultDisplayTile() { return Tile::tnt; }
void MinecartTNT::tick() {
Minecart::tick();
if (fuse > 0) {
fuse--;
level->addParticle(eParticleType_smoke, x, y + 0.5f, z, 0, 0, 0);
} else if (fuse == 0) {
explode(xd * xd + zd * zd);
}
if (horizontalCollision) {
double speedSqr = xd * xd + zd * zd;
if (speedSqr >= 0.01f) {
explode(speedSqr);
}
}
}
void MinecartTNT::destroy(DamageSource* source) {
Minecart::destroy(source);
double speedSqr = xd * xd + zd * zd;
if (!source->isExplosion()) {
spawnAtLocation(
std::shared_ptr<ItemInstance>(new ItemInstance(Tile::tnt, 1)), 0);
}
if (source->isFire() || source->isExplosion() || speedSqr >= 0.01f) {
explode(speedSqr);
}
}
void MinecartTNT::explode(double speedSqr) {
if (!level->isClientSide) {
double speed = sqrt(speedSqr);
if (speed > 5) speed = 5;
level->explode(shared_from_this(), x, y, z,
(float)(4 + random->nextDouble() * 1.5f * speed), true);
remove();
}
}
void MinecartTNT::causeFallDamage(float distance) {
if (distance >= 3) {
float power = distance / 10;
explode(power * power);
}
Minecart::causeFallDamage(distance);
}
void MinecartTNT::activateMinecart(int xt, int yt, int zt, bool state) {
if (state && fuse < 0) {
primeFuse();
}
}
void MinecartTNT::handleEntityEvent(uint8_t eventId) {
if (eventId == EVENT_PRIME) {
primeFuse();
} else {
Minecart::handleEntityEvent(eventId);
}
}
void MinecartTNT::primeFuse() {
fuse = 80;
if (!level->isClientSide) {
level->broadcastEntityEvent(shared_from_this(), EVENT_PRIME);
level->playEntitySound(shared_from_this(), eSoundType_RANDOM_FUSE, 1,
1.0f);
}
}
int MinecartTNT::getFuse() { return fuse; }
bool MinecartTNT::isPrimed() { return fuse > -1; }
float MinecartTNT::getTileExplosionResistance(Explosion* explosion,
Level* level, int x, int y, int z,
Tile* tile) {
if (isPrimed() && (BaseRailTile::isRail(tile->id) ||
BaseRailTile::isRail(level, x, y + 1, z))) {
return 0;
}
return Minecart::getTileExplosionResistance(explosion, level, x, y, z,
tile);
}
bool MinecartTNT::shouldTileExplode(Explosion* explosion, Level* level, int x,
int y, int z, int id, float power) {
if (isPrimed() &&
(BaseRailTile::isRail(id) || BaseRailTile::isRail(level, x, y + 1, z)))
return false;
return Minecart::shouldTileExplode(explosion, level, x, y, z, id, power);
}
void MinecartTNT::readAdditionalSaveData(CompoundTag* tag) {
Minecart::readAdditionalSaveData(tag);
if (tag->contains(L"TNTFuse")) fuse = tag->getInt(L"TNTFuse");
}
void MinecartTNT::addAdditonalSaveData(CompoundTag* tag) {
Minecart::addAdditonalSaveData(tag);
tag->putInt(L"TNTFuse", fuse);
}

View file

@ -0,0 +1,44 @@
#pragma once
#include "Mobs/Minecart.h"
class MinecartTNT : public Minecart {
public:
eINSTANCEOF GetType() { return eTYPE_MINECART_TNT; };
static Entity* create(Level* level) { return new MinecartTNT(level); }
private:
static const uint8_t EVENT_PRIME = 10;
int fuse;
void _init();
public:
MinecartTNT(Level* level);
MinecartTNT(Level* level, double x, double y, double z);
virtual int getType();
virtual Tile* getDefaultDisplayTile();
virtual void tick();
virtual void destroy(DamageSource* source);
protected:
virtual void explode(double speedSqr);
virtual void causeFallDamage(float distance);
public:
virtual void activateMinecart(int xt, int yt, int zt, bool state);
virtual void handleEntityEvent(uint8_t eventId);
virtual void primeFuse();
virtual int getFuse();
virtual bool isPrimed();
virtual float getTileExplosionResistance(Explosion* explosion, Level* level,
int x, int y, int z, Tile* tile);
virtual bool shouldTileExplode(Explosion* explosion, Level* level, int x,
int y, int z, int id, float power);
protected:
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void addAdditonalSaveData(CompoundTag* tag);
};

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
#pragma once
#include "Entity.h"
#include "LivingEntity.h"
#include "MobType.h"
#include "../AI/Goals/GoalSelector.h"
@ -18,106 +18,33 @@ class PathNavigation;
class Sensing;
class Icon;
class Pos;
class MobGroupData;
class Mob : public Entity {
class Mob : public LivingEntity {
friend class MobSpawner;
protected:
// 4J - added for common ctor code
void _init();
public:
Mob(Level* level);
virtual ~Mob();
// 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts
eINSTANCEOF GetType() { return eTYPE_MOB; }
static Entity* create(Level* level) { return NULL; }
public:
static const int ATTACK_DURATION = 5;
static const int PLAYER_HURT_EXPERIENCE_TIME = 20 * 3;
public: // 4J Stu - Made public
static const int DATA_EFFECT_COLOR_ID = 8;
static const float MAX_WEARING_ARMOR_CHANCE;
static const float MAX_PICKUP_LOOT_CHANCE;
static const float MAX_ENCHANTED_ARMOR_CHANCE;
static const float MAX_ENCHANTED_WEAPON_CHANCE;
private:
static const double MIN_MOVEMENT_DISTANCE;
public:
int invulnerableDuration;
float timeOffs;
float rotA;
float yBodyRot, yBodyRotO;
float yHeadRot, yHeadRotO;
protected:
float oRun, run;
float animStep, animStepO;
bool hasHair;
// std::wstring textureName;
int textureIdx; // 4J changed from std::wstring textureName
bool allowAlpha;
float rotOffs;
std::wstring modelName;
float bobStrength;
int deathScore;
float renderOffset;
public:
float walkingSpeed;
float flyingSpeed;
float oAttackAnim, attackAnim;
protected:
int health;
public:
int lastHealth;
protected:
int dmgSpill;
static const int DATA_CUSTOM_NAME = 10;
static const int DATA_CUSTOM_NAME_VISIBLE = 11;
public:
int ambientSoundTime;
int hurtTime;
int hurtDuration;
float hurtDir;
int deathTime;
int attackTime;
float oTilt, tilt;
protected:
bool dead;
int xpReward;
public:
int modelNum;
float animSpeed;
float walkAnimSpeedO;
float walkAnimSpeed;
float walkAnimPos;
protected:
std::shared_ptr<Player> lastHurtByPlayer;
int lastHurtByPlayerTime;
private:
std::shared_ptr<Mob> lastHurtByMob;
int lastHurtByMobTime;
std::shared_ptr<Mob> lastHurtMob;
public:
int arrowCount;
int removeArrowTime;
protected:
std::map<int, MobEffectInstance*> activeEffects;
private:
bool effectsDirty;
int effectColor;
LookControl* lookControl;
MoveControl* moveControl;
JumpControl* jumpControl;
@ -129,12 +56,28 @@ protected:
GoalSelector targetSelector;
private:
std::shared_ptr<Mob> target;
std::shared_ptr<LivingEntity> target;
Sensing* sensing;
float speed;
Pos* restrictCenter;
float restrictRadius;
ItemInstanceArray equipment;
protected:
floatArray dropChances;
private:
bool _canPickUpLoot;
bool persistenceRequired;
protected:
// 4J - added for common ctor code
void _init();
public:
Mob(Level* level);
virtual ~Mob();
protected:
void registerAttributes();
public:
virtual LookControl* getLookControl();
@ -142,152 +85,46 @@ public:
virtual JumpControl* getJumpControl();
virtual PathNavigation* getNavigation();
virtual Sensing* getSensing();
virtual Random* getRandom();
virtual std::shared_ptr<Mob> getLastHurtByMob();
virtual std::shared_ptr<Mob> getLastHurtMob();
void setLastHurtMob(std::shared_ptr<Entity> target);
virtual int getNoActionTime();
float getYHeadRot();
void setYHeadRot(float yHeadRot);
float getSpeed();
void setSpeed(float speed);
virtual bool doHurtTarget(std::shared_ptr<Entity> target);
std::shared_ptr<Mob> getTarget();
virtual void setTarget(std::shared_ptr<Mob> target);
std::shared_ptr<LivingEntity> getTarget();
virtual void setTarget(std::shared_ptr<LivingEntity> target);
virtual bool canAttackType(eINSTANCEOF targetType);
virtual void ate();
bool isWithinRestriction();
bool isWithinRestriction(int x, int y, int z);
void restrictTo(int x, int y, int z, int radius);
Pos* getRestrictCenter();
float getRestrictRadius();
void clearRestriction();
bool hasRestriction();
virtual void setLastHurtByMob(std::shared_ptr<Mob> hurtBy);
protected:
virtual void defineSynchedData();
public:
bool canSee(std::shared_ptr<Entity> target);
virtual int getTexture(); // 4J - changed from std::wstring to int
virtual bool isPickable();
virtual bool isPushable();
virtual float getHeadHeight();
virtual int getAmbientSoundInterval();
void playAmbientSound();
virtual void baseTick();
protected:
virtual void tickDeath();
virtual int decreaseAirSupply(int currentSupply);
virtual int getExperienceReward(std::shared_ptr<Player> killedBy);
virtual bool isAlwaysExperienceDropper();
public:
void spawnAnim();
virtual void rideTick();
protected:
int lSteps;
double lx, ly, lz, lyr, lxr;
public:
virtual void lerpTo(double x, double y, double z, float yRot, float xRot,
int steps);
private:
float fallTime;
public:
void superTick();
virtual void spawnAnim();
virtual void tick();
virtual void heal(int heal);
virtual int getMaxHealth() = 0;
virtual int getHealth();
virtual void setHealth(int health);
protected:
int lastHurt;
public:
virtual bool hurt(DamageSource* source, int dmg);
protected:
float getVoicePitch();
public:
virtual void animateHurt();
/**
* Fetches the mob's armor value, from 0 (no armor) to 20 (full armor)
*
* @return
*/
virtual int getArmorValue();
protected:
virtual void hurtArmor(int damage);
virtual int getDamageAfterArmorAbsorb(DamageSource* damageSource,
int damage);
virtual int getDamageAfterMagicAbsorb(DamageSource* damageSource,
int damage);
virtual void actuallyHurt(DamageSource* source, int dmg);
virtual float getSoundVolume();
virtual float tickHeadTurn(float yBodyRotT, float walkSpeed);
virtual int getAmbientSound();
virtual int getHurtSound();
virtual int getDeathSound();
public:
void knockback(std::shared_ptr<Entity> source, int dmg, double xd,
double zd);
virtual void die(DamageSource* source);
protected:
virtual void dropRareDeathLoot(int rareLootLevel);
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
virtual int getDeathLoot();
virtual void causeFallDamage(float distance);
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
public:
virtual void travel(float xa, float ya);
virtual bool onLadder();
virtual bool isShootable();
virtual void addAdditonalSaveData(CompoundTag* entityTag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual bool isAlive();
virtual bool isWaterMob();
virtual int getLightColor(float a); // 4J - added
protected:
int noActionTime;
float xxa, yya, yRotA;
bool jumping;
float defaultLookAngle;
float runSpeed;
protected:
int noJumpDelay;
public:
virtual void setYya(float yya);
virtual void setJumping(bool jump);
virtual void setSpeed(float speed);
virtual void aiStep();
protected:
virtual bool useNewAi();
virtual bool isEffectiveAI();
virtual bool isImmobile();
public:
virtual bool isBlocking();
protected:
virtual void jumpFromGround();
virtual bool removeWhenFarAway();
private:
@ -298,7 +135,6 @@ protected:
virtual void checkDespawn();
virtual void newServerAiStep();
virtual void serverAiMobStep();
virtual void serverAiStep();
public:
@ -314,62 +150,80 @@ private:
public:
virtual bool canSpawn();
protected:
virtual void outOfWorld();
public:
float getAttackAnim(float a);
virtual Vec3* getPos(float a);
virtual Vec3* getLookAngle();
Vec3* getViewVector(float a);
virtual float getSizeScale();
virtual float getHeadSizeScale();
HitResult* pick(double range, float a);
virtual int getMaxSpawnClusterSize();
virtual int getMaxFallDistance();
virtual std::shared_ptr<ItemInstance> getCarriedItem();
virtual std::shared_ptr<ItemInstance> getCarried(int slot);
virtual std::shared_ptr<ItemInstance> getArmor(int pos);
virtual void handleEntityEvent(uint8_t id);
virtual bool isSleeping();
virtual Icon* getItemInHandIcon(std::shared_ptr<ItemInstance> item,
int layer);
virtual void setEquippedSlot(int slot, std::shared_ptr<ItemInstance> item);
virtual ItemInstanceArray getEquipmentSlots();
protected:
virtual void dropEquipment(bool byPlayer, int playerBonusLevel);
virtual void populateDefaultEquipmentSlots();
public:
static int getEquipmentSlotForItem(std::shared_ptr<ItemInstance> item);
static Item* getEquipmentForSlot(int slot, int type);
protected:
virtual void populateDefaultEquipmentEnchantments();
public:
/**
* Added this method so mobs can handle their own spawn settings instead of
* hacking MobSpawner.java
*
* @param groupData
* TODO
* @return TODO
*/
virtual MobGroupData* finalizeMobSpawn(
MobGroupData* groupData,
int extraData = 0); // 4J Added extraData param
virtual void finalizeSpawnEggSpawn(int extraData); // 4J Added
virtual bool canBeControlledByRider();
virtual std::wstring getAName();
virtual void setPersistenceRequired();
virtual void setCustomName(const std::wstring& name);
virtual std::wstring getCustomName();
virtual bool hasCustomName();
virtual void setCustomNameVisible(bool visible);
virtual bool isCustomNameVisible();
virtual bool shouldShowName();
virtual void setDropChance(int slot, float pct);
virtual bool canPickUpLoot();
virtual void setCanPickUpLoot(bool canPickUpLoot);
virtual bool isPersistenceRequired();
virtual bool interact(std::shared_ptr<Player> player);
protected:
virtual bool mobInteract(std::shared_ptr<Player> player);
// roper / leash methods
private:
bool _isLeashed;
std::shared_ptr<Entity> leashHolder;
CompoundTag* leashInfoTag;
protected:
virtual void tickLeash();
public:
virtual void dropLeash(bool synch, bool createItemDrop);
virtual bool canBeLeashed();
virtual bool isLeashed();
virtual std::shared_ptr<Entity> getLeashHolder();
virtual void setLeashedTo(std::shared_ptr<Entity> holder, bool synch);
private:
virtual void restoreLeashFromSave();
virtual bool shouldRender(Vec3* c);
protected:
void tickEffects();
public:
void removeAllEffects();
std::vector<MobEffectInstance*>* getActiveEffects();
bool hasEffect(int id);
bool hasEffect(MobEffect* effect);
MobEffectInstance* getEffect(MobEffect* effect);
void addEffect(MobEffectInstance* newEffect);
void addEffectNoUpdate(MobEffectInstance* newEffect); // 4J Added
virtual bool canBeAffected(MobEffectInstance* newEffect);
virtual bool isInvertedHealAndHarm();
void removeEffectNoUpdate(int effectId);
void removeEffect(int effectId);
protected:
virtual void onEffectAdded(MobEffectInstance* effect);
virtual void onEffectUpdated(MobEffectInstance* effect);
virtual void onEffectRemoved(MobEffectInstance* effect);
public:
virtual float getWalkingSpeedModifier();
// 4J-Pb added (from 1.2.3)
virtual void teleportTo(double x, double y, double z);
virtual bool isBaby();
virtual MobType getMobType();
virtual void breakItem(std::shared_ptr<ItemInstance> itemInstance);
virtual bool isInvulnerable();
virtual void finalizeMobSpawn();
virtual bool canBeControlledByRider();
// 4J Added override to update ai elements when loading entity from
// schematics
virtual void setLevel(Level* level);

View file

@ -7,47 +7,54 @@
MobCategory* MobCategory::monster = NULL;
MobCategory* MobCategory::creature = NULL;
MobCategory* MobCategory::ambient = NULL;
MobCategory* MobCategory::waterCreature = NULL;
// 4J - added these extra categories
MobCategory* MobCategory::creature_wolf = NULL;
MobCategory* MobCategory::creature_chicken = NULL;
MobCategory* MobCategory::creature_mushroomcow = NULL;
MobCategoryArray MobCategory::values = MobCategoryArray(6);
MobCategoryArray MobCategory::values = MobCategoryArray(7);
void MobCategory::staticCtor() {
// 4J - adjusted the max levels here for the xbox version, which now
// represent the max levels in the whole world
monster = new MobCategory(70, Material::air, false, eTYPE_MONSTER, false,
CONSOLE_MONSTERS_HARD_LIMIT);
creature = new MobCategory(10, Material::air, true,
monster = new MobCategory(70, Material::air, false, false, eTYPE_MONSTER,
false, CONSOLE_MONSTERS_HARD_LIMIT);
creature = new MobCategory(10, Material::air, true, true,
eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false,
CONSOLE_ANIMALS_HARD_LIMIT);
waterCreature = new MobCategory(5, Material::water, true, eTYPE_WATERANIMAL,
false, CONSOLE_SQUID_HARD_LIMIT);
ambient = new MobCategory(15, Material::air, true, false, eTYPE_AMBIENT,
false, CONSOLE_AMBIENT_HARD_LIMIT),
waterCreature =
new MobCategory(5, Material::water, true, false, eTYPE_WATERANIMAL,
false, CONSOLE_SQUID_HARD_LIMIT);
values[0] = monster;
values[1] = creature;
values[2] = waterCreature;
values[2] = ambient;
values[3] = waterCreature;
// 4J - added 2 new categories to give us better control over spawning
// wolves & chickens
creature_wolf = new MobCategory(3, Material::air, true, eTYPE_WOLF, true,
MAX_XBOX_WOLVES);
creature_chicken = new MobCategory(2, Material::air, true, eTYPE_CHICKEN,
true, MAX_XBOX_CHICKENS);
creature_mushroomcow = new MobCategory(
2, Material::air, true, eTYPE_MUSHROOMCOW, true, MAX_XBOX_MUSHROOMCOWS);
values[3] = creature_wolf;
values[4] = creature_chicken;
values[5] = creature_mushroomcow;
creature_wolf = new MobCategory(3, Material::air, true, true, eTYPE_WOLF,
true, MAX_XBOX_WOLVES);
creature_chicken = new MobCategory(2, Material::air, true, true,
eTYPE_CHICKEN, true, MAX_XBOX_CHICKENS);
creature_mushroomcow =
new MobCategory(2, Material::air, true, true, eTYPE_MUSHROOMCOW, true,
MAX_XBOX_MUSHROOMCOWS);
values[4] = creature_wolf;
values[5] = creature_chicken;
values[6] = creature_mushroomcow;
}
MobCategory::MobCategory(int maxVar, Material* spawnPositionMaterial,
bool isFriendly, eINSTANCEOF eBase, bool isSingleType,
int maxPerLevel)
bool isFriendly, bool isPersistent, eINSTANCEOF eBase,
bool isSingleType, int maxPerLevel)
: m_max(maxVar),
spawnPositionMaterial(spawnPositionMaterial),
m_isFriendly(isFriendly),
m_isPersistent(isPersistent),
m_eBase(eBase),
m_isSingleType(isSingleType),
m_maxPerLevel(maxPerLevel) {}
@ -69,3 +76,5 @@ Material* MobCategory::getSpawnPositionMaterial() {
bool MobCategory::isFriendly() { return m_isFriendly; }
bool MobCategory::isSingleType() { return m_isSingleType; }
bool MobCategory::isPersistent() { return m_isPersistent; }

View file

@ -12,6 +12,7 @@ public:
static const int CONSOLE_ANIMALS_HARD_LIMIT =
50; // Max number of animals (cows, sheep, pigs) that the mob spawner
// will produce
static const int CONSOLE_AMBIENT_HARD_LIMIT = 20; // Ambient mobs
static const int MAX_XBOX_CHICKENS =
8; // Max number of chickens that the mob spawner will produce
@ -26,6 +27,8 @@ public:
16; // Max number of iron golems that can be created by placing blocks
// - 4J-PB increased limit due to player requests
static const int CONSOLE_SQUID_HARD_LIMIT = 5;
static const int MAX_CONSOLE_BOSS =
1; // Max number of bosses (enderdragon/wither)
static const int MAX_XBOX_ANIMALS_WITH_BREEDING =
CONSOLE_ANIMALS_HARD_LIMIT + 20; // Max number of animals that we can
@ -56,6 +59,8 @@ public:
MAX_XBOX_MUSHROOMCOWS_WITH_BREEDING + 8;
static const int MAX_XBOX_SQUIDS_WITH_SPAWN_EGG =
CONSOLE_SQUID_HARD_LIMIT + 8;
static const int MAX_AMBIENT_WITH_SPAWN_EGG =
CONSOLE_AMBIENT_HARD_LIMIT + 8;
/*
Maximum animals = 50 + 20 + 20 = 90
@ -74,6 +79,7 @@ public:
static MobCategory* monster;
static MobCategory* creature;
static MobCategory* ambient;
static MobCategory* waterCreature;
// 4J added extra categories, to break these out of general creatures & give
// us more control of levels
@ -91,11 +97,13 @@ private:
const int m_maxPerLevel;
const Material* spawnPositionMaterial;
const bool m_isFriendly;
const bool m_isPersistent;
const bool m_isSingleType; // 4J Added
const eINSTANCEOF m_eBase; // 4J added
MobCategory(int maxVar, Material* spawnPositionMaterial, bool isFriendly,
eINSTANCEOF eBase, bool isSingleType, int maxPerLevel);
bool isPersistent, eINSTANCEOF eBase, bool isSingleType,
int maxPerLevel);
public:
const std::type_info getBaseClass();
@ -105,6 +113,7 @@ public:
Material* getSpawnPositionMaterial();
bool isFriendly();
bool isSingleType();
bool isPersistent();
public:
static void staticCtor();

View file

@ -1,5 +1,9 @@
#include "../Platform/stdafx.h"
#include "../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../Headers/net.minecraft.world.entity.player.h"
#include "../Headers/net.minecraft.world.entity.monster.h"
#include "../Headers/net.minecraft.world.entity.h"
#include "../Headers/net.minecraft.world.level.h"
#include "../Headers/net.minecraft.world.damagesource.h"
#include "../Headers/net.minecraft.world.food.h"
#include "../Headers/net.minecraft.world.effect.h"
@ -7,119 +11,195 @@
MobEffect* MobEffect::effects[NUM_EFFECTS];
MobEffect* MobEffect::voidEffect = NULL;
MobEffect* MobEffect::movementSpeed =
(new MobEffect(1, false, eMinecraftColour_Effect_MovementSpeed))
->setDescriptionId(IDS_POTION_MOVESPEED)
->setPostfixDescriptionId(IDS_POTION_MOVESPEED_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Speed); // setIcon(0, 0);
MobEffect* MobEffect::movementSlowdown =
(new MobEffect(2, true, eMinecraftColour_Effect_MovementSlowDown))
->setDescriptionId(IDS_POTION_MOVESLOWDOWN)
->setPostfixDescriptionId(IDS_POTION_MOVESLOWDOWN_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Slowness); //->setIcon(1, 0);
MobEffect* MobEffect::digSpeed =
(new MobEffect(3, false, eMinecraftColour_Effect_DigSpeed))
->setDescriptionId(IDS_POTION_DIGSPEED)
->setPostfixDescriptionId(IDS_POTION_DIGSPEED_POSTFIX)
->setDurationModifier(1.5)
->setIcon(MobEffect::e_MobEffectIcon_Haste); //->setIcon(2, 0);
MobEffect* MobEffect::digSlowdown =
(new MobEffect(4, true, eMinecraftColour_Effect_DigSlowdown))
->setDescriptionId(IDS_POTION_DIGSLOWDOWN)
->setPostfixDescriptionId(IDS_POTION_DIGSLOWDOWN_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_MiningFatigue); //->setIcon(3, 0);
MobEffect* MobEffect::damageBoost =
(new MobEffect(5, false, eMinecraftColour_Effect_DamageBoost))
->setDescriptionId(IDS_POTION_DAMAGEBOOST)
->setPostfixDescriptionId(IDS_POTION_DAMAGEBOOST_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Strength); //->setIcon(4, 0);
MobEffect* MobEffect::heal =
(new InstantenousMobEffect(6, false, eMinecraftColour_Effect_Heal))
->setDescriptionId(IDS_POTION_HEAL)
->setPostfixDescriptionId(IDS_POTION_HEAL_POSTFIX);
MobEffect* MobEffect::harm =
(new InstantenousMobEffect(7, true, eMinecraftColour_Effect_Harm))
->setDescriptionId(IDS_POTION_HARM)
->setPostfixDescriptionId(IDS_POTION_HARM_POSTFIX);
MobEffect* MobEffect::jump =
(new MobEffect(8, false, eMinecraftColour_Effect_Jump))
->setDescriptionId(IDS_POTION_JUMP)
->setPostfixDescriptionId(IDS_POTION_JUMP_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_JumpBoost); //->setIcon(2, 1);
MobEffect* MobEffect::confusion =
(new MobEffect(9, true, eMinecraftColour_Effect_Confusion))
->setDescriptionId(IDS_POTION_CONFUSION)
->setPostfixDescriptionId(IDS_POTION_CONFUSION_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Nausea); //->setIcon(3, 1);
MobEffect* MobEffect::regeneration =
(new MobEffect(10, false, eMinecraftColour_Effect_Regeneration))
->setDescriptionId(IDS_POTION_REGENERATION)
->setPostfixDescriptionId(IDS_POTION_REGENERATION_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Regeneration); //->setIcon(7, 0);
MobEffect* MobEffect::damageResistance =
(new MobEffect(11, false, eMinecraftColour_Effect_DamageResistance))
->setDescriptionId(IDS_POTION_RESISTANCE)
->setPostfixDescriptionId(IDS_POTION_RESISTANCE_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Resistance); //->setIcon(6, 1);
MobEffect* MobEffect::fireResistance =
(new MobEffect(12, false, eMinecraftColour_Effect_FireResistance))
->setDescriptionId(IDS_POTION_FIRERESISTANCE)
->setPostfixDescriptionId(IDS_POTION_FIRERESISTANCE_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_FireResistance); //->setIcon(7, 1);
MobEffect* MobEffect::waterBreathing =
(new MobEffect(13, false, eMinecraftColour_Effect_WaterBreathing))
->setDescriptionId(IDS_POTION_WATERBREATHING)
->setPostfixDescriptionId(IDS_POTION_WATERBREATHING_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_WaterBreathing); //->setIcon(0, 2);
MobEffect* MobEffect::invisibility =
(new MobEffect(14, false, eMinecraftColour_Effect_Invisiblity))
->setDescriptionId(IDS_POTION_INVISIBILITY)
->setPostfixDescriptionId(IDS_POTION_INVISIBILITY_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Invisiblity); //->setIcon(0, 1);
MobEffect* MobEffect::blindness =
(new MobEffect(15, true, eMinecraftColour_Effect_Blindness))
->setDescriptionId(IDS_POTION_BLINDNESS)
->setPostfixDescriptionId(IDS_POTION_BLINDNESS_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Blindness); //->setIcon(5, 1);
MobEffect* MobEffect::nightVision =
(new MobEffect(16, false, eMinecraftColour_Effect_NightVision))
->setDescriptionId(IDS_POTION_NIGHTVISION)
->setPostfixDescriptionId(IDS_POTION_NIGHTVISION_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_NightVision); //->setIcon(4, 1);
MobEffect* MobEffect::hunger =
(new MobEffect(17, true, eMinecraftColour_Effect_Hunger))
->setDescriptionId(IDS_POTION_HUNGER)
->setPostfixDescriptionId(IDS_POTION_HUNGER_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Hunger); //->setIcon(1, 1);
MobEffect* MobEffect::weakness =
(new MobEffect(18, true, eMinecraftColour_Effect_Weakness))
->setDescriptionId(IDS_POTION_WEAKNESS)
->setPostfixDescriptionId(IDS_POTION_WEAKNESS_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Weakness); //->setIcon(5, 0);
MobEffect* MobEffect::poison =
(new MobEffect(19, true, eMinecraftColour_Effect_Poison))
->setDescriptionId(IDS_POTION_POISON)
->setPostfixDescriptionId(IDS_POTION_POISON_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Poison); //->setIcon(6, 0);
MobEffect* MobEffect::reserved_20 = NULL;
MobEffect* MobEffect::reserved_21 = NULL;
MobEffect* MobEffect::reserved_22 = NULL;
MobEffect* MobEffect::reserved_23 = NULL;
MobEffect* MobEffect::reserved_24 = NULL;
MobEffect* MobEffect::reserved_25 = NULL;
MobEffect* MobEffect::reserved_26 = NULL;
MobEffect* MobEffect::reserved_27 = NULL;
MobEffect* MobEffect::reserved_28 = NULL;
MobEffect* MobEffect::reserved_29 = NULL;
MobEffect* MobEffect::reserved_30 = NULL;
MobEffect* MobEffect::reserved_31 = NULL;
MobEffect* MobEffect::voidEffect;
MobEffect* MobEffect::movementSpeed;
MobEffect* MobEffect::movementSlowdown;
MobEffect* MobEffect::digSpeed;
MobEffect* MobEffect::digSlowdown;
MobEffect* MobEffect::damageBoost;
MobEffect* MobEffect::heal;
MobEffect* MobEffect::harm;
MobEffect* MobEffect::jump;
MobEffect* MobEffect::confusion;
MobEffect* MobEffect::regeneration;
MobEffect* MobEffect::damageResistance;
MobEffect* MobEffect::fireResistance;
MobEffect* MobEffect::waterBreathing;
MobEffect* MobEffect::invisibility;
MobEffect* MobEffect::blindness;
MobEffect* MobEffect::nightVision;
MobEffect* MobEffect::hunger;
MobEffect* MobEffect::weakness;
MobEffect* MobEffect::poison;
MobEffect* MobEffect::wither;
MobEffect* MobEffect::healthBoost;
MobEffect* MobEffect::absorption;
MobEffect* MobEffect::saturation;
MobEffect* MobEffect::reserved_24;
MobEffect* MobEffect::reserved_25;
MobEffect* MobEffect::reserved_26;
MobEffect* MobEffect::reserved_27;
MobEffect* MobEffect::reserved_28;
MobEffect* MobEffect::reserved_29;
MobEffect* MobEffect::reserved_30;
MobEffect* MobEffect::reserved_31;
void MobEffect::staticCtor() {
voidEffect = NULL;
movementSpeed =
(new MobEffect(1, false, eMinecraftColour_Effect_MovementSpeed))
->setDescriptionId(IDS_POTION_MOVESPEED)
->setPostfixDescriptionId(IDS_POTION_MOVESPEED_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Speed)
->addAttributeModifier(
SharedMonsterAttributes::MOVEMENT_SPEED,
eModifierId_POTION_MOVESPEED, 0.2f,
AttributeModifier::OPERATION_MULTIPLY_TOTAL); // setIcon(0, 0);
movementSlowdown =
(new MobEffect(2, true, eMinecraftColour_Effect_MovementSlowDown))
->setDescriptionId(IDS_POTION_MOVESLOWDOWN)
->setPostfixDescriptionId(IDS_POTION_MOVESLOWDOWN_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Slowness)
->addAttributeModifier(
SharedMonsterAttributes::MOVEMENT_SPEED,
eModifierId_POTION_MOVESLOWDOWN, -0.15f,
AttributeModifier::OPERATION_MULTIPLY_TOTAL); //->setIcon(1,
// 0);
digSpeed =
(new MobEffect(3, false, eMinecraftColour_Effect_DigSpeed))
->setDescriptionId(IDS_POTION_DIGSPEED)
->setPostfixDescriptionId(IDS_POTION_DIGSPEED_POSTFIX)
->setDurationModifier(1.5)
->setIcon(MobEffect::e_MobEffectIcon_Haste); //->setIcon(2, 0);
digSlowdown =
(new MobEffect(4, true, eMinecraftColour_Effect_DigSlowdown))
->setDescriptionId(IDS_POTION_DIGSLOWDOWN)
->setPostfixDescriptionId(IDS_POTION_DIGSLOWDOWN_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_MiningFatigue); //->setIcon(3, 0);
damageBoost =
(new AttackDamageMobEffect(5, false,
eMinecraftColour_Effect_DamageBoost))
->setDescriptionId(IDS_POTION_DAMAGEBOOST)
->setPostfixDescriptionId(IDS_POTION_DAMAGEBOOST_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Strength)
->addAttributeModifier(
SharedMonsterAttributes::ATTACK_DAMAGE,
eModifierId_POTION_DAMAGEBOOST, 3,
AttributeModifier::OPERATION_MULTIPLY_TOTAL); //->setIcon(4,
// 0);
heal = (new InstantenousMobEffect(6, false, eMinecraftColour_Effect_Heal))
->setDescriptionId(IDS_POTION_HEAL)
->setPostfixDescriptionId(IDS_POTION_HEAL_POSTFIX);
harm = (new InstantenousMobEffect(7, true, eMinecraftColour_Effect_Harm))
->setDescriptionId(IDS_POTION_HARM)
->setPostfixDescriptionId(IDS_POTION_HARM_POSTFIX);
jump =
(new MobEffect(8, false, eMinecraftColour_Effect_Jump))
->setDescriptionId(IDS_POTION_JUMP)
->setPostfixDescriptionId(IDS_POTION_JUMP_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_JumpBoost); //->setIcon(2, 1);
confusion =
(new MobEffect(9, true, eMinecraftColour_Effect_Confusion))
->setDescriptionId(IDS_POTION_CONFUSION)
->setPostfixDescriptionId(IDS_POTION_CONFUSION_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Nausea); //->setIcon(3, 1);
regeneration =
(new MobEffect(10, false, eMinecraftColour_Effect_Regeneration))
->setDescriptionId(IDS_POTION_REGENERATION)
->setPostfixDescriptionId(IDS_POTION_REGENERATION_POSTFIX)
->setDurationModifier(.25)
->setIcon(
MobEffect::e_MobEffectIcon_Regeneration); //->setIcon(7, 0);
damageResistance =
(new MobEffect(11, false, eMinecraftColour_Effect_DamageResistance))
->setDescriptionId(IDS_POTION_RESISTANCE)
->setPostfixDescriptionId(IDS_POTION_RESISTANCE_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_Resistance); //->setIcon(6, 1);
fireResistance =
(new MobEffect(12, false, eMinecraftColour_Effect_FireResistance))
->setDescriptionId(IDS_POTION_FIRERESISTANCE)
->setPostfixDescriptionId(IDS_POTION_FIRERESISTANCE_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_FireResistance); //->setIcon(7, 1);
waterBreathing =
(new MobEffect(13, false, eMinecraftColour_Effect_WaterBreathing))
->setDescriptionId(IDS_POTION_WATERBREATHING)
->setPostfixDescriptionId(IDS_POTION_WATERBREATHING_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_WaterBreathing); //->setIcon(0, 2);
invisibility =
(new MobEffect(14, false, eMinecraftColour_Effect_Invisiblity))
->setDescriptionId(IDS_POTION_INVISIBILITY)
->setPostfixDescriptionId(IDS_POTION_INVISIBILITY_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_Invisiblity); //->setIcon(0, 1);
blindness =
(new MobEffect(15, true, eMinecraftColour_Effect_Blindness))
->setDescriptionId(IDS_POTION_BLINDNESS)
->setPostfixDescriptionId(IDS_POTION_BLINDNESS_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Blindness); //->setIcon(5, 1);
nightVision =
(new MobEffect(16, false, eMinecraftColour_Effect_NightVision))
->setDescriptionId(IDS_POTION_NIGHTVISION)
->setPostfixDescriptionId(IDS_POTION_NIGHTVISION_POSTFIX)
->setIcon(
MobEffect::e_MobEffectIcon_NightVision); //->setIcon(4, 1);
hunger =
(new MobEffect(17, true, eMinecraftColour_Effect_Hunger))
->setDescriptionId(IDS_POTION_HUNGER)
->setPostfixDescriptionId(IDS_POTION_HUNGER_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Hunger); //->setIcon(1, 1);
weakness =
(new AttackDamageMobEffect(18, true, eMinecraftColour_Effect_Weakness))
->setDescriptionId(IDS_POTION_WEAKNESS)
->setPostfixDescriptionId(IDS_POTION_WEAKNESS_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Weakness)
->addAttributeModifier(
SharedMonsterAttributes::ATTACK_DAMAGE,
eModifierId_POTION_WEAKNESS, 2,
AttributeModifier::OPERATION_ADDITION); //->setIcon(5, 0);
poison =
(new MobEffect(19, true, eMinecraftColour_Effect_Poison))
->setDescriptionId(IDS_POTION_POISON)
->setPostfixDescriptionId(IDS_POTION_POISON_POSTFIX)
->setDurationModifier(.25)
->setIcon(MobEffect::e_MobEffectIcon_Poison); //->setIcon(6, 0);
wither = (new MobEffect(20, true, eMinecraftColour_Effect_Wither))
->setDescriptionId(IDS_POTION_WITHER)
->setPostfixDescriptionId(IDS_POTION_WITHER_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Wither)
->setDurationModifier(.25);
healthBoost =
(new HealthBoostMobEffect(21, false,
eMinecraftColour_Effect_HealthBoost))
->setDescriptionId(IDS_POTION_HEALTHBOOST)
->setPostfixDescriptionId(IDS_POTION_HEALTHBOOST_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_HealthBoost)
->addAttributeModifier(SharedMonsterAttributes::MAX_HEALTH,
eModifierId_POTION_HEALTHBOOST, 4,
AttributeModifier::OPERATION_ADDITION);
absorption =
(new AbsoptionMobEffect(22, false, eMinecraftColour_Effect_Absoprtion))
->setDescriptionId(IDS_POTION_ABSORPTION)
->setPostfixDescriptionId(IDS_POTION_ABSORPTION_POSTFIX)
->setIcon(MobEffect::e_MobEffectIcon_Absorption);
saturation = (new InstantenousMobEffect(23, false,
eMinecraftColour_Effect_Saturation))
->setDescriptionId(IDS_POTION_SATURATION)
->setPostfixDescriptionId(IDS_POTION_SATURATION_POSTFIX);
reserved_24 = NULL;
reserved_25 = NULL;
reserved_26 = NULL;
reserved_27 = NULL;
reserved_28 = NULL;
reserved_29 = NULL;
reserved_30 = NULL;
reserved_31 = NULL;
}
MobEffect::MobEffect(int id, bool isHarmful, eMinecraftColour color)
: id(id), _isHarmful(isHarmful), color(color) {
@ -159,7 +239,8 @@ int MobEffect::getId() { return id; }
* @param mob
* @param amplification
*/
void MobEffect::applyEffectTick(std::shared_ptr<Mob> mob, int amplification) {
void MobEffect::applyEffectTick(std::shared_ptr<LivingEntity> mob,
int amplification) {
// Maybe move this to separate class implementations in the future?
if (id == regeneration->id) {
if (mob->getHealth() < mob->getMaxHealth()) {
@ -169,27 +250,33 @@ void MobEffect::applyEffectTick(std::shared_ptr<Mob> mob, int amplification) {
if (mob->getHealth() > 1) {
mob->hurt(DamageSource::magic, 1);
}
} else if (id == hunger->id &&
std::dynamic_pointer_cast<Player>(mob) != NULL) {
} else if (id == wither->id) {
mob->hurt(DamageSource::wither, 1);
} else if ((id == hunger->id) && mob->instanceof(eTYPE_PLAYER)) {
// every tick, cause the same amount of exhaustion as when removing
// a block, times amplification
std::dynamic_pointer_cast<Player>(mob)->causeFoodExhaustion(
FoodConstants::EXHAUSTION_MINE * (amplification + 1));
} else if ((id == saturation->id) && mob->instanceof(eTYPE_PLAYER)) {
if (!mob->level->isClientSide) {
std::dynamic_pointer_cast<Player>(mob)->getFoodData()->eat(
amplification + 1, FoodConstants::FOOD_SATURATION_MAX);
}
} else if ((id == heal->id && !mob->isInvertedHealAndHarm()) ||
(id == harm->id && mob->isInvertedHealAndHarm())) {
mob->heal(6 << amplification);
mob->heal(std::max(4 << amplification, 0));
} else if ((id == harm->id && !mob->isInvertedHealAndHarm()) ||
(id == heal->id && mob->isInvertedHealAndHarm())) {
mob->hurt(DamageSource::magic, 6 << amplification);
}
}
void MobEffect::applyInstantenousEffect(std::shared_ptr<Mob> source,
std::shared_ptr<Mob> mob,
void MobEffect::applyInstantenousEffect(std::shared_ptr<LivingEntity> source,
std::shared_ptr<LivingEntity> mob,
int amplification, double scale) {
if ((id == heal->id && !mob->isInvertedHealAndHarm()) ||
(id == harm->id && mob->isInvertedHealAndHarm())) {
int amount = (int)(scale * (double)(6 << amplification) + .5);
int amount = (int)(scale * (double)(4 << amplification) + .5);
mob->heal(amount);
} else if ((id == harm->id && !mob->isInvertedHealAndHarm()) ||
(id == heal->id && mob->isInvertedHealAndHarm())) {
@ -219,13 +306,26 @@ bool MobEffect::isInstantenous() { return false; }
*/
bool MobEffect::isDurationEffectTick(int remainingDuration, int amplification) {
// Maybe move this to separate class implementations in the future?
if (id == regeneration->id || id == poison->id) {
if (id == regeneration->id) {
// tick intervals are 50, 25, 12, 6..
int interval = 50 >> amplification;
if (interval > 0) {
return (remainingDuration % interval) == 0;
}
return true;
} else if (id == poison->id) {
// tick intervals are 25, 12, 6..
int interval = 25 >> amplification;
if (interval > 0) {
return (remainingDuration % interval) == 0;
}
return true;
} else if (id == wither->id) {
int interval = 40 >> amplification;
if (interval > 0) {
return (remainingDuration % interval) == 0;
}
return true;
} else if (id == hunger->id) {
return true;
}
@ -256,6 +356,9 @@ MobEffect::EMobEffectIcon MobEffect::getIcon() { return icon; }
bool MobEffect::isHarmful() { return _isHarmful; }
std::wstring MobEffect::formatDuration(MobEffectInstance* instance) {
if (instance->isNoCounter()) {
return L"**:**";
}
int duration = instance->getDuration();
int seconds = duration / SharedConstants::TICKS_PER_SECOND;
@ -284,10 +387,60 @@ MobEffect* MobEffect::setDurationModifier(double durationModifier) {
double MobEffect::getDurationModifier() { return durationModifier; }
MobEffect* MobEffect::setDisabled() {
this->_isDisabled = true;
_isDisabled = true;
return this;
}
bool MobEffect::isDisabled() { return _isDisabled; }
eMinecraftColour MobEffect::getColor() { return color; }
MobEffect* MobEffect::addAttributeModifier(Attribute* attribute,
eMODIFIER_ID id, double amount,
int operation) {
AttributeModifier* effect = new AttributeModifier(id, amount, operation);
attributeModifiers.insert(
std::pair<Attribute*, AttributeModifier*>(attribute, effect));
return this;
}
std::unordered_map<Attribute*, AttributeModifier*>*
MobEffect::getAttributeModifiers() {
return &attributeModifiers;
}
void MobEffect::removeAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes,
int amplifier) {
for (AUTO_VAR(it, attributeModifiers.begin());
it != attributeModifiers.end(); ++it) {
AttributeInstance* attribute = attributes->getInstance(it->first);
if (attribute != NULL) {
attribute->removeModifier(it->second);
}
}
}
void MobEffect::addAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes,
int amplifier) {
for (AUTO_VAR(it, attributeModifiers.begin());
it != attributeModifiers.end(); ++it) {
AttributeInstance* attribute = attributes->getInstance(it->first);
if (attribute != NULL) {
AttributeModifier* original = it->second;
attribute->removeModifier(original);
attribute->addModifier(new AttributeModifier(
original->getId(),
getAttributeModifierValue(amplifier, original),
original->getOperation()));
}
}
}
double MobEffect::getAttributeModifierValue(int amplifier,
AttributeModifier* original) {
return original->getAmount() * (amplifier + 1);
}

View file

@ -1,7 +1,10 @@
#pragma once
#include "../AI/Attributes/AttributeModifier.h"
class Mob;
class MobEffectInstance;
class Attribute;
class MobEffect {
public:
@ -24,6 +27,9 @@ public:
e_MobEffectIcon_Strength,
e_MobEffectIcon_WaterBreathing,
e_MobEffectIcon_Weakness,
e_MobEffectIcon_Wither,
e_MobEffectIcon_HealthBoost,
e_MobEffectIcon_Absorption,
e_MobEffectIcon_COUNT,
};
@ -51,10 +57,10 @@ public:
static MobEffect* hunger;
static MobEffect* weakness;
static MobEffect* poison;
static MobEffect* reserved_20;
static MobEffect* reserved_21;
static MobEffect* reserved_22;
static MobEffect* reserved_23;
static MobEffect* wither;
static MobEffect* healthBoost;
static MobEffect* absorption;
static MobEffect* saturation;
static MobEffect* reserved_24;
static MobEffect* reserved_25;
static MobEffect* reserved_26;
@ -66,7 +72,10 @@ public:
const int id;
static void staticCtor();
private:
std::unordered_map<Attribute*, AttributeModifier*> attributeModifiers;
int descriptionId;
int m_postfixDescriptionId; // 4J added
EMobEffectIcon icon; // 4J changed type
@ -82,11 +91,12 @@ protected:
MobEffect* setIcon(EMobEffectIcon icon);
public:
int getId();
void applyEffectTick(std::shared_ptr<Mob> mob, int amplification);
void applyInstantenousEffect(std::shared_ptr<Mob> source,
std::shared_ptr<Mob> mob, int amplification,
double scale);
virtual int getId();
virtual void applyEffectTick(std::shared_ptr<LivingEntity> mob,
int amplification);
virtual void applyInstantenousEffect(std::shared_ptr<LivingEntity> source,
std::shared_ptr<LivingEntity> mob,
int amplification, double scale);
virtual bool isInstantenous();
virtual bool isDurationEffectTick(int remainingDuration, int amplification);
@ -106,8 +116,22 @@ protected:
MobEffect* setDurationModifier(double durationModifier);
public:
double getDurationModifier();
MobEffect* setDisabled();
bool isDisabled();
eMinecraftColour getColor();
virtual double getDurationModifier();
virtual MobEffect* setDisabled();
virtual bool isDisabled();
virtual eMinecraftColour getColor();
virtual MobEffect* addAttributeModifier(Attribute* attribute,
eMODIFIER_ID id, double amount,
int operation);
virtual std::unordered_map<Attribute*, AttributeModifier*>*
getAttributeModifiers();
virtual void removeAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes,
int amplifier);
virtual void addAttributeModifiers(std::shared_ptr<LivingEntity> entity,
BaseAttributeMap* attributes,
int amplifier);
virtual double getAttributeModifierValue(int amplifier,
AttributeModifier* original);
};

View file

@ -5,6 +5,10 @@ void MobEffectInstance::_init(int id, int duration, int amplifier) {
this->id = id;
this->duration = duration;
this->amplifier = amplifier;
splash = false;
ambient = false;
noCounter = false;
}
MobEffectInstance::MobEffectInstance(int id) { _init(id, 0, 0); }
@ -17,23 +21,34 @@ MobEffectInstance::MobEffectInstance(int id, int duration, int amplifier) {
_init(id, duration, amplifier);
}
MobEffectInstance::MobEffectInstance(int id, int duration, int amplifier,
bool ambient) {
_init(id, duration, amplifier);
this->ambient = ambient;
}
MobEffectInstance::MobEffectInstance(MobEffectInstance* copy) {
this->id = copy->id;
this->duration = copy->duration;
this->amplifier = copy->amplifier;
this->splash = copy->splash;
this->ambient = copy->ambient;
this->noCounter = copy->noCounter;
}
void MobEffectInstance::update(MobEffectInstance* takeOver) {
if (this->id != takeOver->id) {
if (id != takeOver->id) {
app.DebugPrintf(
"This method should only be called for matching effects!");
}
if (takeOver->amplifier > this->amplifier) {
this->amplifier = takeOver->amplifier;
this->duration = takeOver->duration;
} else if (takeOver->amplifier == this->amplifier &&
this->duration < takeOver->duration) {
this->duration = takeOver->duration;
if (takeOver->amplifier > amplifier) {
amplifier = takeOver->amplifier;
duration = takeOver->duration;
} else if (takeOver->amplifier == amplifier &&
duration < takeOver->duration) {
duration = takeOver->duration;
} else if (!takeOver->ambient && ambient) {
ambient = takeOver->ambient;
}
}
@ -43,13 +58,19 @@ int MobEffectInstance::getDuration() { return duration; }
int MobEffectInstance::getAmplifier() { return amplifier; }
bool MobEffectInstance::isSplash() { return splash; }
void MobEffectInstance::setSplash(bool splash) { this->splash = splash; }
bool MobEffectInstance::isAmbient() { return ambient; }
/**
* Runs the effect on a Mob target.
*
* @param target
* @return True if the effect is still active.
*/
bool MobEffectInstance::tick(std::shared_ptr<Mob> target) {
bool MobEffectInstance::tick(std::shared_ptr<LivingEntity> target) {
if (duration > 0) {
if (MobEffect::effects[id]->isDurationEffectTick(duration, amplifier)) {
applyEffect(target);
@ -61,7 +82,7 @@ bool MobEffectInstance::tick(std::shared_ptr<Mob> target) {
int MobEffectInstance::tickDownDuration() { return --duration; }
void MobEffectInstance::applyEffect(std::shared_ptr<Mob> mob) {
void MobEffectInstance::applyEffect(std::shared_ptr<LivingEntity> mob) {
if (duration > 0) {
MobEffect::effects[id]->applyEffectTick(mob, amplifier);
}
@ -88,11 +109,11 @@ int MobEffectInstance::hashCode() {
std::wstring MobEffectInstance::toString() {
std::wstring result =
L"MobEffectInstance::toString - NON IMPLEMENTED OR LOCALISED FUNCTION";
// std::wstring result = "";
// wstring result = "";
// if (getAmplifier() > 0)
//{
// result = getDescriptionId() + " x " + (getAmplifier() + 1) + ",
//Duration: " + getDuration();
// Duration: " + getDuration();
// }
// else
//{
@ -106,7 +127,30 @@ std::wstring MobEffectInstance::toString() {
}
// Was bool equals(Object obj)
bool MobEffectInstance::equals(MobEffectInstance* obj) {
return this->id == obj->id && this->amplifier == obj->amplifier &&
this->duration == obj->duration;
bool MobEffectInstance::equals(MobEffectInstance* instance) {
return id == instance->id && amplifier == instance->amplifier &&
duration == instance->duration && splash == instance->splash &&
ambient == instance->ambient;
}
CompoundTag* MobEffectInstance::save(CompoundTag* tag) {
tag->putByte(L"Id", (uint8_t)getId());
tag->putByte(L"Amplifier", (uint8_t)getAmplifier());
tag->putInt(L"Duration", getDuration());
tag->putBoolean(L"Ambient", isAmbient());
return tag;
}
MobEffectInstance* MobEffectInstance::load(CompoundTag* tag) {
int id = tag->getByte(L"Id");
int amplifier = tag->getByte(L"Amplifier");
int duration = tag->getInt(L"Duration");
boolean ambient = tag->getBoolean(L"Ambient");
return new MobEffectInstance(id, duration, amplifier, ambient);
}
void MobEffectInstance::setNoCounter(bool noCounter) {
this->noCounter = noCounter;
}
bool MobEffectInstance::isNoCounter() { return noCounter; }

View file

@ -10,6 +10,9 @@ private:
int duration;
// sent as byte
int amplifier;
bool splash;
bool ambient;
bool noCounter;
void _init(int id, int duration, int amplifier);
@ -17,19 +20,25 @@ public:
MobEffectInstance(int id);
MobEffectInstance(int id, int duration);
MobEffectInstance(int id, int duration, int amplifier);
MobEffectInstance(int id, int duration, int amplifier, bool ambient);
MobEffectInstance(MobEffectInstance* copy);
void update(MobEffectInstance* takeOver);
int getId();
int getDuration();
int getAmplifier();
bool tick(std::shared_ptr<Mob> target);
bool isSplash();
void setSplash(bool splash);
bool isAmbient();
bool tick(std::shared_ptr<LivingEntity> target);
private:
int tickDownDuration();
public:
void applyEffect(std::shared_ptr<Mob> mob);
void applyEffect(std::shared_ptr<LivingEntity> mob);
int getDescriptionId();
int getPostfixDescriptionId(); // 4J Added
int hashCode();
@ -38,4 +47,9 @@ public:
// Was bool equals(Object obj)
bool equals(MobEffectInstance* obj);
CompoundTag* save(CompoundTag* tag);
static MobEffectInstance* load(CompoundTag* tag);
void setNoCounter(bool noCounter);
bool isNoCounter();
};

View file

@ -12,10 +12,10 @@ AgableMob::AgableMob(Level* level) : PathfinderMob(level) {
registeredBBHeight = 0;
}
bool AgableMob::interact(std::shared_ptr<Player> player) {
bool AgableMob::mobInteract(std::shared_ptr<Player> player) {
std::shared_ptr<ItemInstance> item = player->inventory->getSelected();
if (item != NULL && item->id == Item::monsterPlacer_Id) {
if (item != NULL && item->id == Item::spawnEgg_Id) {
if (!level->isClientSide) {
eINSTANCEOF classToSpawn = EntityIO::getClass(item->getAuxValue());
if (classToSpawn != eTYPE_NOTSET &&
@ -23,28 +23,38 @@ bool AgableMob::interact(std::shared_ptr<Player> player) {
classToSpawn == GetType()) // 4J Added GetType() check to only
// spawn same type
{
std::shared_ptr<AgableMob> offspring = getBreedOffspring(
std::dynamic_pointer_cast<AgableMob>(shared_from_this()));
if (offspring != NULL) {
offspring->setAge(-20 * 60 * 20);
offspring->moveTo(x, y, z, 0, 0);
int error;
std::shared_ptr<Entity> result =
SpawnEggItem::canSpawn(item->getAuxValue(), level, &error);
level->addEntity(offspring);
if (result != NULL) {
std::shared_ptr<AgableMob> offspring =
getBreedOffspring(std::dynamic_pointer_cast<AgableMob>(
shared_from_this()));
if (offspring != NULL) {
offspring->setAge(BABY_START_AGE);
offspring->moveTo(x, y, z, 0, 0);
if (!player->abilities.instabuild) {
item->count--;
level->addEntity(offspring);
if (item->count <= 0) {
player->inventory->setItem(
player->inventory->selected, nullptr);
if (!player->abilities.instabuild) {
item->count--;
if (item->count <= 0) {
player->inventory->setItem(
player->inventory->selected, nullptr);
}
}
}
} else {
SpawnEggItem::DisplaySpawnError(player, error);
}
}
}
return true;
}
return PathfinderMob::interact(player);
return false;
}
void AgableMob::defineSynchedData() {
@ -54,6 +64,15 @@ void AgableMob::defineSynchedData() {
int AgableMob::getAge() { return entityData->getInteger(DATA_AGE_ID); }
void AgableMob::ageUp(int seconds) {
int age = getAge();
age += seconds * SharedConstants::TICKS_PER_SECOND;
if (age > 0) {
age = 0;
}
setAge(age);
}
void AgableMob::setAge(int age) {
entityData->set(DATA_AGE_ID, age);
updateSize(isBaby());

View file

@ -6,13 +6,17 @@ class AgableMob : public PathfinderMob {
private:
static const int DATA_AGE_ID = 12;
public:
static const int BABY_START_AGE = -20 * 60 * 20;
private:
float registeredBBWidth;
float registeredBBHeight;
public:
AgableMob(Level* level);
virtual bool interact(std::shared_ptr<Player> player);
virtual bool mobInteract(std::shared_ptr<Player> player);
protected:
virtual void defineSynchedData();
@ -21,6 +25,7 @@ public:
virtual std::shared_ptr<AgableMob> getBreedOffspring(
std::shared_ptr<AgableMob> target) = 0;
virtual int getAge();
virtual void ageUp(int seconds);
virtual void setAge(int age);
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);

View file

@ -0,0 +1,11 @@
#include "../../Platform/stdafx.h"
#include "AmbientCreature.h"
AmbientCreature::AmbientCreature(Level* level) : Mob(level) {}
bool AmbientCreature::canBeLeashed() { return false; }
bool AmbientCreature::mobInteract(std::shared_ptr<Player> player) {
return false;
}

View file

@ -0,0 +1,14 @@
#pragma once
#include "../Mob.h"
#include "Creature.h"
class AmbientCreature : public Mob, public Creature {
public:
AmbientCreature(Level* level);
virtual bool canBeLeashed();
protected:
virtual bool mobInteract(std::shared_ptr<Player> player);
};

View file

@ -1,4 +1,5 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/com.mojang.nbt.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
#include "../../Headers/net.minecraft.world.item.h"
@ -9,6 +10,8 @@
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.projectile.h"
#include "../../Headers/net.minecraft.world.damagesource.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Util/Random.h"
#include "Animal.h"
@ -57,7 +60,8 @@ void Animal::aiStep() {
}
void Animal::checkHurtTarget(std::shared_ptr<Entity> target, float d) {
if (std::dynamic_pointer_cast<Player>(target) != NULL) {
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
if (target->instanceof(eTYPE_PLAYER)) {
if (d < 3) {
double xd = target->x - x;
double zd = target->z - z;
@ -67,13 +71,13 @@ void Animal::checkHurtTarget(std::shared_ptr<Entity> target, float d) {
}
std::shared_ptr<Player> p = std::dynamic_pointer_cast<Player>(target);
if (p->getSelectedItem() != NULL &&
this->isFood(p->getSelectedItem())) {
} else {
if (p->getSelectedItem() == NULL || !isFood(p->getSelectedItem())) {
attackTarget = nullptr;
}
} else if (std::dynamic_pointer_cast<Animal>(target) != NULL) {
}
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
else if (target->instanceof(eTYPE_ANIMAL)) {
std::shared_ptr<Animal> a = std::dynamic_pointer_cast<Animal>(target);
if (getAge() > 0 && a->getAge() < 0) {
if (d < 2.5) {
@ -152,20 +156,26 @@ float Animal::getWalkTargetValue(int x, int y, int z) {
return level->getBrightness(x, y, z) - 0.5f;
}
bool Animal::hurt(DamageSource* dmgSource, int dmg) {
bool Animal::hurt(DamageSource* dmgSource, float dmg) {
if (isInvulnerable()) return false;
if (dynamic_cast<EntityDamageSource*>(dmgSource) != NULL) {
std::shared_ptr<Entity> source = dmgSource->getDirectEntity();
if (std::dynamic_pointer_cast<Player>(source) != NULL &&
// 4J-JEV: Changed from dynamic cast to use eINSTANCEOF
if (source->instanceof(eTYPE_PLAYER) &&
!std::dynamic_pointer_cast<Player>(source)
->isAllowedToAttackAnimals()) {
return false;
}
if (source != NULL && source->GetType() == eTYPE_ARROW) {
if ((source != NULL) && source->instanceof(eTYPE_ARROW)) {
std::shared_ptr<Arrow> arrow =
std::dynamic_pointer_cast<Arrow>(source);
if (std::dynamic_pointer_cast<Player>(arrow->owner) != NULL &&
// 4J: Check that the arrow's owner can attack animals (dispenser
// arrows are not owned)
if (arrow->owner != NULL &&
arrow->owner->instanceof(eTYPE_PLAYER) &&
!std::dynamic_pointer_cast<Player>(arrow->owner)
->isAllowedToAttackAnimals()) {
return false;
@ -174,6 +184,16 @@ bool Animal::hurt(DamageSource* dmgSource, int dmg) {
}
fleeTime = 20 * 3;
if (!useNewAi()) {
AttributeInstance* speed =
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
if (speed->getModifier(eModifierId_MOB_FLEEING) == NULL) {
speed->addModifier(
new AttributeModifier(*Animal::SPEED_MODIFIER_FLEEING));
}
}
attackTarget = nullptr;
setInLoveValue(0);
@ -265,9 +285,10 @@ bool Animal::isFood(std::shared_ptr<ItemInstance> itemInstance) {
return itemInstance->id == Item::wheat_Id;
}
bool Animal::interact(std::shared_ptr<Player> player) {
bool Animal::mobInteract(std::shared_ptr<Player> player) {
std::shared_ptr<ItemInstance> item = player->inventory->getSelected();
if (item != NULL && isFood(item) && getAge() == 0) {
if (item != NULL && isFood(item) && getAge() == 0 &&
getInLoveValue() <= 0) {
if (!player->abilities.instabuild) {
item->count--;
if (item->count <= 0) {
@ -311,28 +332,17 @@ bool Animal::interact(std::shared_ptr<Player> player) {
return false;
}
} else if ((GetType() & eTYPE_MONSTER) == eTYPE_MONSTER) {
} else if (instanceof(eTYPE_MONSTER)) {
}
break;
}
setInLove(player);
}
attackTarget = nullptr;
for (int i = 0; i < 7; i++) {
double xa = random->nextGaussian() * 0.02;
double ya = random->nextGaussian() * 0.02;
double za = random->nextGaussian() * 0.02;
level->addParticle(eParticleType_heart,
x + random->nextFloat() * bbWidth * 2 - bbWidth,
y + .5f + random->nextFloat() * bbHeight,
z + random->nextFloat() * bbWidth * 2 - bbWidth,
xa, ya, za);
}
setInLove();
return true;
}
return AgableMob::interact(player);
return AgableMob::mobInteract(player);
}
// 4J added
@ -348,18 +358,41 @@ void Animal::setInLove(std::shared_ptr<Player> player) {
std::shared_ptr<Player> Animal::getLoveCause() { return loveCause.lock(); }
void Animal::setInLove() {
entityData->set(DATA_IN_LOVE, 20 * 30);
attackTarget = nullptr;
level->broadcastEntityEvent(shared_from_this(),
EntityEvent::IN_LOVE_HEARTS);
}
bool Animal::isInLove() { return entityData->getInteger(DATA_IN_LOVE) > 0; }
void Animal::resetLove() { entityData->set(DATA_IN_LOVE, 0); }
bool Animal::canMate(std::shared_ptr<Animal> partner) {
if (partner == shared_from_this()) return false;
Animal* partnerPtr = partner.get();
if (partnerPtr == NULL || typeid(*partnerPtr) != typeid(*this))
return false;
if (typeid(*partner) != typeid(*this)) return false;
return isInLove() && partner->isInLove();
}
void Animal::handleEntityEvent(uint8_t id) {
if (id == EntityEvent::IN_LOVE_HEARTS) {
for (int i = 0; i < 7; i++) {
double xa = random->nextGaussian() * 0.02;
double ya = random->nextGaussian() * 0.02;
double za = random->nextGaussian() * 0.02;
level->addParticle(eParticleType_heart,
x + random->nextFloat() * bbWidth * 2 - bbWidth,
y + .5f + random->nextFloat() * bbHeight,
z + random->nextFloat() * bbWidth * 2 - bbWidth,
xa, ya, za);
}
} else {
AgableMob::handleEntityEvent(id);
}
}
void Animal::updateDespawnProtectedState() {
if (level->isClientSide) return;
@ -375,7 +408,7 @@ void Animal::updateDespawnProtectedState() {
if (((m_maxWanderX - m_minWanderX) > MAX_WANDER_DISTANCE) ||
((m_maxWanderZ - m_minWanderZ) > MAX_WANDER_DISTANCE)) {
// printf("Unprotecting : %d to %d, %d to %d\n",
//m_minWanderX, m_maxWanderX, m_minWanderZ, m_maxWanderZ );
// m_minWanderX, m_maxWanderX, m_minWanderZ, m_maxWanderZ );
m_isDespawnProtected = false;
}
@ -403,4 +436,4 @@ void Animal::setDespawnProtected() {
m_maxWanderZ = zt;
m_isDespawnProtected = true;
}
}

View file

@ -11,7 +11,7 @@ private:
static const int DATA_IN_LOVE = 13; // 4J added
// int inLove; // 4J
//removed - now synched data
// removed - now synched data
int loveTime;
std::weak_ptr<Player> loveCause;
@ -35,7 +35,7 @@ public:
virtual float getWalkTargetValue(int x, int y, int z);
public:
virtual bool hurt(DamageSource* source, int dmg);
virtual bool hurt(DamageSource* source, float dmg);
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
@ -52,7 +52,7 @@ protected:
public:
virtual bool isFood(std::shared_ptr<ItemInstance> itemInstance);
virtual bool interact(std::shared_ptr<Player> player);
virtual bool mobInteract(std::shared_ptr<Player> player);
protected:
int getInLoveValue(); // 4J added
@ -62,10 +62,12 @@ public:
void setInLove(std::shared_ptr<Player>
player); // 4J added, then modified to match latest Java
// for XboxOne achievements
virtual void setInLove();
std::shared_ptr<Player> getLoveCause();
bool isInLove();
void resetLove();
virtual bool canMate(std::shared_ptr<Animal> partner);
virtual void handleEntityEvent(uint8_t id);
// 4J added for determining whether animals are enclosed or not
private:

View file

@ -7,6 +7,9 @@
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.damagesource.h"
#include "../../Headers/net.minecraft.world.item.enchantment.h"
#include "../../Headers/net.minecraft.network.packet.h"
#include "../../../Minecraft.Client/Player/ServerPlayer.h"
#include "../../../Minecraft.Client/Network/PlayerConnection.h"
#include "../../Headers/com.mojang.nbt.h"
#include "Arrow.h"
@ -44,16 +47,19 @@ void Arrow::_init() {
Arrow::Arrow(Level* level) : Entity(level) {
_init();
this->setSize(0.5f, 0.5f);
viewScale = 10;
setSize(0.5f, 0.5f);
}
Arrow::Arrow(Level* level, std::shared_ptr<Mob> mob,
std::shared_ptr<Mob> target, float power, float uncertainty)
Arrow::Arrow(Level* level, std::shared_ptr<LivingEntity> mob,
std::shared_ptr<LivingEntity> target, float power,
float uncertainty)
: Entity(level) {
_init();
this->owner = mob;
if (std::dynamic_pointer_cast<Player>(mob) != NULL) pickup = PICKUP_ALLOWED;
viewScale = 10;
owner = mob;
if (mob->instanceof(eTYPE_PLAYER)) pickup = PICKUP_ALLOWED;
y = mob->y + mob->getHeadHeight() - 0.1f;
@ -78,29 +84,30 @@ Arrow::Arrow(Level* level, std::shared_ptr<Mob> mob,
Arrow::Arrow(Level* level, double x, double y, double z) : Entity(level) {
_init();
this->setSize(0.5f, 0.5f);
viewScale = 10;
setSize(0.5f, 0.5f);
this->setPos(x, y, z);
this->heightOffset = 0;
setPos(x, y, z);
heightOffset = 0;
}
Arrow::Arrow(Level* level, std::shared_ptr<Mob> mob, float power)
Arrow::Arrow(Level* level, std::shared_ptr<LivingEntity> mob, float power)
: Entity(level) {
_init();
this->owner = mob;
if (std::dynamic_pointer_cast<Player>(mob) != NULL) pickup = PICKUP_ALLOWED;
viewScale = 10;
owner = mob;
if (mob->instanceof(eTYPE_PLAYER)) pickup = PICKUP_ALLOWED;
setSize(0.5f, 0.5f);
this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot,
mob->xRot);
moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot);
x -= Mth::cos(yRot / 180 * PI) * 0.16f;
y -= 0.1f;
z -= Mth::sin(yRot / 180 * PI) * 0.16f;
this->setPos(x, y, z);
this->heightOffset = 0;
setPos(x, y, z);
heightOffset = 0;
xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI);
@ -119,9 +126,12 @@ void Arrow::shoot(double xd, double yd, double zd, float pow,
yd /= dist;
zd /= dist;
xd += (random->nextGaussian()) * 0.0075f * uncertainty;
yd += (random->nextGaussian()) * 0.0075f * uncertainty;
zd += (random->nextGaussian()) * 0.0075f * uncertainty;
xd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) *
0.0075f * uncertainty;
yd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) *
0.0075f * uncertainty;
zd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) *
0.0075f * uncertainty;
xd *= pow;
yd *= pow;
@ -133,8 +143,8 @@ void Arrow::shoot(double xd, double yd, double zd, float pow,
double sd = sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = this->xRot = (float)(atan2(yd, sd) * 180 / PI);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, sd) * 180 / PI);
life = 0;
}
@ -150,8 +160,8 @@ void Arrow::lerpMotion(double xd, double yd, double zd) {
this->zd = zd;
if (xRotO == 0 && yRotO == 0) {
double sd = sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = this->xRot = (float)(atan2(yd, sd) * 180 / PI);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, sd) * 180 / PI);
xRotO = xRot;
yRotO = yRot;
app.DebugPrintf("%f %f : 0x%x\n", xRot, yRot, &yRot);
@ -165,8 +175,8 @@ void Arrow::tick() {
if (xRotO == 0 && yRotO == 0) {
double sd = sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = this->xRot = (float)(atan2(yd, sd) * 180 / PI);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, sd) * 180 / PI);
}
{
@ -243,6 +253,20 @@ void Arrow::tick() {
res = new HitResult(hitEntity);
}
if ((res != NULL) && (res->entity != NULL) &&
res->entity->instanceof(eTYPE_PLAYER)) {
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(res->entity);
// 4J: Check for owner being null
if (player->abilities.invulnerable ||
((owner != NULL) &&
(owner->instanceof(eTYPE_PLAYER) &&
!std::dynamic_pointer_cast<Player>(owner)->canHarmPlayer(
player)))) {
res = NULL;
}
}
if (res != NULL) {
if (res->entity != NULL) {
float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd);
@ -268,14 +292,17 @@ void Arrow::tick() {
// unless we can cause some damage (this doesn't necessarily
// mean that the arrow hit lowered their health) set targets on
// fire first because we want cooked pork/chicken/steak
if (this->isOnFire()) {
if (isOnFire() && res->entity->GetType() != eTYPE_ENDERMAN) {
res->entity->setOnFire(5);
}
std::shared_ptr<Mob> mob =
std::dynamic_pointer_cast<Mob>(res->entity);
if (mob != NULL) {
mob->arrowCount++;
if (res->entity->instanceof(eTYPE_LIVINGENTITY)) {
std::shared_ptr<LivingEntity> mob =
std::dynamic_pointer_cast<LivingEntity>(res->entity);
if (!level->isClientSide) {
mob->setArrowCount(mob->getArrowCount() + 1);
}
if (knockback > 0) {
float pushLen = sqrt(xd * xd + zd * zd);
if (pushLen > 0) {
@ -289,15 +316,23 @@ void Arrow::tick() {
ThornsEnchantment::doThornsAfterAttack(owner, mob,
random);
}
if (owner != NULL && res->entity != owner &&
owner->GetType() == eTYPE_SERVERPLAYER) {
std::dynamic_pointer_cast<ServerPlayer>(owner)
->connection->send(std::shared_ptr<GameEventPacket>(
new GameEventPacket(
GameEventPacket::SUCCESSFUL_BOW_HIT, 0)));
}
}
// 4J : WESTY : For award, need to track if creeper was killed
// by arrow from the player.
if ((std::dynamic_pointer_cast<Player>(owner) !=
NULL) && // arrow owner is a player
(res->entity->isAlive() == false) && // target is now dead
(std::dynamic_pointer_cast<Creeper>(res->entity) !=
NULL)) // target is a creeper
if (owner != NULL &&
owner->instanceof(eTYPE_PLAYER) // arrow owner is a player
&& !res->entity->isAlive() // target is now dead
&& (res->entity->GetType() ==
eTYPE_CREEPER)) // target is a creeper
{
std::dynamic_pointer_cast<Player>(owner)->awardStat(
@ -305,11 +340,9 @@ void Arrow::tick() {
GenericStats::param_arrowKillCreeper());
}
// 4J - sound change brought forward from 1.2.3
level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT,
1.0f,
1.2f / (random->nextFloat() * 0.2f + 0.9f));
remove();
playSound(eSoundType_RANDOM_BOW_HIT, 1.0f,
1.2f / (random->nextFloat() * 0.2f + 0.9f));
if (res->entity->GetType() != eTYPE_ENDERDRAGON) remove();
} else {
xd *= -0.1f;
yd *= -0.1f;
@ -337,12 +370,16 @@ void Arrow::tick() {
z -= (zd / dd) * 0.05f;
}
// 4J - sound change brought forward from 1.2.3
level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT,
1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f));
playSound(eSoundType_RANDOM_BOW_HIT, 1.0f,
1.2f / (random->nextFloat() * 0.2f + 0.9f));
inGround = true;
shakeTime = 7;
setCritArrow(false);
if (lastTile != 0) {
Tile::tiles[lastTile]->entityInside(level, xTile, yTile, zTile,
shared_from_this());
}
}
}
delete res;
@ -441,14 +478,16 @@ void Arrow::playerTouch(std::shared_ptr<Player> player) {
}
if (bRemove) {
level->playSound(
shared_from_this(), eSoundType_RANDOM_POP, 0.2f,
playSound(
eSoundType_RANDOM_POP, 0.2f,
((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f);
player->take(shared_from_this(), 1);
remove();
}
}
bool Arrow::makeStepSound() { return false; }
float Arrow::getShadowHeightOffs() { return 0; }
void Arrow::setBaseDamage(double baseDamage) { this->baseDamage = baseDamage; }

View file

@ -1,11 +1,12 @@
#pragma once
#include "../Entity.h"
#include "../Projectile.h"
class Level;
class CompoundTag;
class Arrow : public Entity {
class Arrow : public Entity, public Projectile {
public:
eINSTANCEOF GetType() { return eTYPE_ARROW; }
static Entity* create(Level* level) { return new Arrow(level); }
@ -50,10 +51,10 @@ private:
public:
Arrow(Level* level);
Arrow(Level* level, std::shared_ptr<Mob> mob, std::shared_ptr<Mob> target,
float power, float uncertainty);
Arrow(Level* level, std::shared_ptr<LivingEntity> mob,
std::shared_ptr<LivingEntity> target, float power, float uncertainty);
Arrow(Level* level, double x, double y, double z);
Arrow(Level* level, std::shared_ptr<Mob> mob, float power);
Arrow(Level* level, std::shared_ptr<LivingEntity> mob, float power);
protected:
virtual void defineSynchedData();
@ -67,6 +68,11 @@ public:
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void playerTouch(std::shared_ptr<Player> player);
protected:
virtual bool makeStepSound();
public:
virtual float getShadowHeightOffs();
void setBaseDamage(double baseDamage);

View file

@ -0,0 +1,208 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
#include "../../Headers/net.minecraft.world.phys.h"
#include "Bat.h"
Bat::Bat(Level* level) : AmbientCreature(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
registerAttributes();
setHealth(getMaxHealth());
targetPosition = NULL;
setSize(.5f, .9f);
setResting(true);
}
void Bat::defineSynchedData() {
AmbientCreature::defineSynchedData();
entityData->define(DATA_ID_FLAGS, (char)0);
}
float Bat::getSoundVolume() { return 0.1f; }
float Bat::getVoicePitch() { return AmbientCreature::getVoicePitch() * .95f; }
int Bat::getAmbientSound() {
if (isResting() && random->nextInt(4) != 0) {
return -1;
}
return eSoundType_MOB_BAT_IDLE; //"mob.bat.idle";
}
int Bat::getHurtSound() {
return eSoundType_MOB_BAT_HURT; //"mob.bat.hurt";
}
int Bat::getDeathSound() {
return eSoundType_MOB_BAT_DEATH; //"mob.bat.death";
}
bool Bat::isPushable() {
// bats can't be pushed by other mobs
return false;
}
void Bat::doPush(std::shared_ptr<Entity> e) {
// bats don't push other mobs
}
void Bat::pushEntities() {
// bats don't push other mobs
}
void Bat::registerAttributes() {
AmbientCreature::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(6);
}
bool Bat::isResting() {
return (entityData->getByte(DATA_ID_FLAGS) & FLAG_RESTING) != 0;
}
void Bat::setResting(bool value) {
char current = entityData->getByte(DATA_ID_FLAGS);
if (value) {
entityData->set(DATA_ID_FLAGS, (char)(current | FLAG_RESTING));
} else {
entityData->set(DATA_ID_FLAGS, (char)(current & ~FLAG_RESTING));
}
}
bool Bat::useNewAi() { return true; }
void Bat::tick() {
AmbientCreature::tick();
if (isResting()) {
xd = yd = zd = 0;
y = Mth::floor(y) + 1.0 - bbHeight;
} else {
yd *= .6f;
}
}
inline int signum(double x) { return (x > 0) - (x < 0); }
void Bat::newServerAiStep() {
AmbientCreature::newServerAiStep();
if (isResting()) {
if (!level->isSolidBlockingTile(Mth::floor(x), (int)y + 1,
Mth::floor(z))) {
setResting(false);
level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int)x,
(int)y, (int)z, 0);
} else {
if (random->nextInt(200) == 0) {
yHeadRot = random->nextInt(360);
}
if (level->getNearestPlayer(shared_from_this(), 4.0f) != NULL) {
setResting(false);
level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF,
(int)x, (int)y, (int)z, 0);
}
}
} else {
if (targetPosition != NULL &&
(!level->isEmptyTile(targetPosition->x, targetPosition->y,
targetPosition->z) ||
targetPosition->y < 1)) {
delete targetPosition;
targetPosition = NULL;
}
if (targetPosition == NULL || random->nextInt(30) == 0 ||
targetPosition->distSqr((int)x, (int)y, (int)z) < 4) {
delete targetPosition;
targetPosition =
new Pos((int)x + random->nextInt(7) - random->nextInt(7),
(int)y + random->nextInt(6) - 2,
(int)z + random->nextInt(7) - random->nextInt(7));
}
double dx = (targetPosition->x + .5) - x;
double dy = (targetPosition->y + .1) - y;
double dz = (targetPosition->z + .5) - z;
xd = xd + (signum(dx) * .5f - xd) * .1f;
yd = yd + (signum(dy) * .7f - yd) * .1f;
zd = zd + (signum(dz) * .5f - zd) * .1f;
float yRotD = (float)(atan2(zd, xd) * 180 / PI) - 90;
float rotDiff = Mth::wrapDegrees(yRotD - yRot);
yya = .5f;
yRot += rotDiff;
if (random->nextInt(100) == 0 &&
level->isSolidBlockingTile(Mth::floor(x), (int)y + 1,
Mth::floor(z))) {
setResting(true);
}
}
}
bool Bat::makeStepSound() { return false; }
void Bat::causeFallDamage(float distance) {}
void Bat::checkFallDamage(double ya, bool onGround) {
// this method is empty because flying creatures should
// not trigger the "fallOn" tile calls (such as trampling crops)
}
bool Bat::isIgnoringTileTriggers() { return true; }
bool Bat::hurt(DamageSource* source, float dmg) {
if (isInvulnerable()) return false;
if (!level->isClientSide) {
if (isResting()) {
setResting(false);
}
}
return AmbientCreature::hurt(source, dmg);
}
void Bat::readAdditionalSaveData(CompoundTag* tag) {
AmbientCreature::readAdditionalSaveData(tag);
entityData->set(DATA_ID_FLAGS, tag->getByte(L"BatFlags"));
}
void Bat::addAdditonalSaveData(CompoundTag* entityTag) {
AmbientCreature::addAdditonalSaveData(entityTag);
entityTag->putByte(L"BatFlags", entityData->getByte(DATA_ID_FLAGS));
}
bool Bat::canSpawn() {
int yt = Mth::floor(bb->y0);
if (yt >= level->seaLevel) return false;
int xt = Mth::floor(x);
int zt = Mth::floor(z);
int br = level->getRawBrightness(xt, yt, zt);
int maxLight = 4;
if ((Calendar::GetDayOfMonth() + 1 == 10 &&
Calendar::GetDayOfMonth() >= 20) ||
(Calendar::GetMonth() + 1 == 11 && Calendar::GetMonth() <= 3)) {
maxLight = 7;
} else if (random->nextBoolean()) {
return false;
}
if (br > random->nextInt(maxLight)) return false;
return AmbientCreature::canSpawn();
}

View file

@ -0,0 +1,57 @@
#pragma once
#include "AmbientCreature.h"
class Bat : public AmbientCreature {
public:
eINSTANCEOF GetType() { return eTYPE_BAT; }
static Entity* create(Level* level) { return new Bat(level); }
private:
static const int DATA_ID_FLAGS = 16;
static const int FLAG_RESTING = 1;
Pos* targetPosition;
public:
Bat(Level* level);
protected:
virtual void defineSynchedData();
virtual float getSoundVolume();
virtual float getVoicePitch();
virtual int getAmbientSound();
virtual int getHurtSound();
virtual int getDeathSound();
public:
virtual bool isPushable();
protected:
virtual void doPush(std::shared_ptr<Entity> e);
virtual void pushEntities();
virtual void registerAttributes();
public:
virtual bool isResting();
virtual void setResting(bool value);
protected:
virtual bool useNewAi();
public:
virtual void tick();
protected:
virtual void newServerAiStep();
virtual bool makeStepSound();
virtual void causeFallDamage(float distance);
virtual void checkFallDamage(double ya, bool onGround);
virtual bool isIgnoringTileTriggers();
public:
virtual bool hurt(DamageSource* source, float dmg);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void addAdditonalSaveData(CompoundTag* entityTag);
virtual bool canSpawn();
};

View file

@ -5,6 +5,8 @@
#include "../../Headers/net.minecraft.world.phys.h"
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.entity.projectile.h"
#include "../../Util/SharedConstants.h"
#include "../../../Minecraft.Client/Textures/Textures.h"
@ -15,17 +17,11 @@ Blaze::Blaze(Level* level) : Monster(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
this->textureIdx = TN_MOB_BLAZE; // 4J Was "/mob/fire.png";
registerAttributes();
setHealth(getMaxHealth());
fireImmune = true;
attackDamage = 6;
xpReward = XP_REWARD_LARGE;
// this.setSize(1.2f, 1.8f);
// 4J Default inits
allowedHeightOffset = 0.5f;
@ -33,7 +29,10 @@ Blaze::Blaze(Level* level) : Monster(level) {
attackCounter = 0;
}
int Blaze::getMaxHealth() { return 20; }
void Blaze::registerAttributes() {
Monster::registerAttributes();
getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(6);
}
void Blaze::defineSynchedData() {
Monster::defineSynchedData();
@ -67,7 +66,7 @@ void Blaze::aiStep() {
if (getAttackTarget() != NULL &&
(getAttackTarget()->y + getAttackTarget()->getHeadHeight()) >
(this->y + getHeadHeight() + allowedHeightOffset)) {
(y + getHeadHeight() + allowedHeightOffset)) {
yd = yd + (.3f - yd) * .3f;
}
}

View file

@ -17,9 +17,9 @@ private:
public:
Blaze(Level* level);
virtual int getMaxHealth();
protected:
virtual void registerAttributes();
virtual void defineSynchedData();
virtual int getAmbientSound();
virtual int getHurtSound();

View file

@ -40,7 +40,7 @@ bool Boat::makeStepSound() { return false; }
void Boat::defineSynchedData() {
entityData->define(DATA_ID_HURT, 0);
entityData->define(DATA_ID_HURTDIR, 1);
entityData->define(DATA_ID_DAMAGE, 0);
entityData->define(DATA_ID_DAMAGE, 0.0f);
}
AABB* Boat::getCollideAgainstBox(std::shared_ptr<Entity> entity) {
@ -66,7 +66,8 @@ Boat::Boat(Level* level, double x, double y, double z) : Entity(level) {
double Boat::getRideHeight() { return bbHeight * 0.0f - 0.3f; }
bool Boat::hurt(DamageSource* source, int hurtDamage) {
bool Boat::hurt(DamageSource* source, float hurtDamage) {
if (isInvulnerable()) return false;
if (level->isClientSide || removed) return true;
// 4J-JEV: Fix for #88212,
@ -74,10 +75,11 @@ bool Boat::hurt(DamageSource* source, int hurtDamage) {
if (dynamic_cast<EntityDamageSource*>(source) != NULL) {
std::shared_ptr<Entity> attacker = source->getDirectEntity();
if (std::dynamic_pointer_cast<Player>(attacker) != NULL &&
if (attacker->instanceof(eTYPE_PLAYER) &&
!std::dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity(
shared_from_this()))
shared_from_this())) {
return false;
}
}
setHurtDir(-getHurtDir());
@ -95,14 +97,16 @@ bool Boat::hurt(DamageSource* source, int hurtDamage) {
// 4J Stu - Brought froward from 12w36 to fix #46611 - TU5: Gameplay:
// Minecarts and boat requires more hits than one to be destroyed in
// creative mode
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(source->getEntity());
if (player != NULL && player->abilities.instabuild) setDamage(100);
// creative mode 4J-PB - Fix for XB1 #175735 - [CRASH] [Multi-Plat]: Code:
// Gameplay: Placing a boat on harmful surfaces causes the game to crash
bool creativePlayer = (source->getEntity() != NULL) &&
source->getEntity()->instanceof(eTYPE_PLAYER) &&
std::dynamic_pointer_cast<Player>(source->getEntity())
->abilities.instabuild;
if (getDamage() > 20 * 2) {
if (creativePlayer || getDamage() > 20 * 2) {
if (rider.lock() != NULL) rider.lock()->ride(shared_from_this());
spawnAtLocation(Item::boat_Id, 1, 0);
if (!creativePlayer) spawnAtLocation(Item::boat_Id, 1, 0);
remove();
}
return true;
@ -139,9 +143,9 @@ void Boat::lerpTo(double x, double y, double z, float yRot, float xRot,
lyr = yRot;
lxr = xRot;
this->xd = lxd;
this->yd = lyd;
this->zd = lzd;
xd = lxd;
yd = lyd;
zd = lzd;
}
void Boat::lerpMotion(double xd, double yd, double zd) {
@ -204,8 +208,8 @@ void Boat::tick() {
xRot += (float)((lxr - xRot) / lSteps);
lSteps--;
this->setPos(xt, yt, zt);
this->setRot(yRot, xRot);
setPos(xt, yt, zt);
setRot(yRot, xRot);
} else {
#if 1
// Original
@ -216,7 +220,7 @@ void Boat::tick() {
// 4J Stu - Fix for various boat bugs, ensure that we check
// collision on client-side movement
this->move(xd, yd, zd);
move(xd, yd, zd);
if (onGround) {
xd *= 0.5f;
@ -269,9 +273,17 @@ void Boat::tick() {
yd += 0.007f;
}
if (rider.lock() != NULL) {
xd += rider.lock()->xd * acceleration;
zd += rider.lock()->zd * acceleration;
if (rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY)) {
std::shared_ptr<LivingEntity> livingRider =
std::dynamic_pointer_cast<LivingEntity>(rider.lock());
double std::forward = livingRider->yya;
if (std::forward > 0) {
double riderXd = -sin(livingRider->yRot * PI / 180);
double riderZd = cos(livingRider->yRot * PI / 180);
xd += riderXd * acceleration * 0.05f;
zd += riderZd * acceleration * 0.05f;
}
}
double curSpeed = sqrt(xd * xd + zd * zd);
@ -300,7 +312,7 @@ void Boat::tick() {
move(xd, yd, zd);
if ((horizontalCollision && lastSpeed > 0.20)) {
if (!level->isClientSide) {
if (!level->isClientSide && !removed) {
remove();
for (int i = 0; i < 3; i++) {
spawnAtLocation(Tile::wood_Id, 1, 0);
@ -334,7 +346,7 @@ void Boat::tick() {
if (level->isClientSide) return;
std::vector<std::shared_ptr<Entity> >* entities =
level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f));
level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f));
if (entities != NULL && !entities->empty()) {
AUTO_VAR(itEnd, entities->end());
for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) {
@ -353,14 +365,11 @@ void Boat::tick() {
for (int j = 0; j < 2; j++) {
int yy = Mth::floor(y) + j;
int tile = level->getTile(xx, yy, zz);
int data = level->getData(xx, yy, zz);
if (tile == Tile::topSnow_Id) {
level->setTile(xx, yy, zz, 0);
level->removeTile(xx, yy, zz);
} else if (tile == Tile::waterLily_Id) {
Tile::waterLily->spawnResources(level, xx, yy, zz, data, 0.3f,
0);
level->setTile(xx, yy, zz, 0);
level->destroyTile(xx, yy, zz, true);
}
}
}
@ -388,9 +397,8 @@ float Boat::getShadowHeightOffs() { return 0; }
std::wstring Boat::getName() { return L"Boat"; }
bool Boat::interact(std::shared_ptr<Player> player) {
if (rider.lock() != NULL &&
std::dynamic_pointer_cast<Player>(rider.lock()) != NULL &&
rider.lock() != player)
if ((rider.lock() != NULL) && rider.lock()->instanceof(eTYPE_PLAYER) &&
(rider.lock() != player))
return true;
if (!level->isClientSide) {
// 4J HEG - Fixed issue with player not being able to dismount boat
@ -400,9 +408,9 @@ bool Boat::interact(std::shared_ptr<Player> player) {
return true;
}
void Boat::setDamage(int damage) { entityData->set(DATA_ID_DAMAGE, damage); }
void Boat::setDamage(float damage) { entityData->set(DATA_ID_DAMAGE, damage); }
int Boat::getDamage() { return entityData->getInteger(DATA_ID_DAMAGE); }
float Boat::getDamage() { return entityData->getFloat(DATA_ID_DAMAGE); }
void Boat::setHurtTime(int hurtTime) {
entityData->set(DATA_ID_HURT, hurtTime);

View file

@ -46,7 +46,7 @@ public:
Boat(Level* level, double x, double y, double z);
virtual double getRideHeight();
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
virtual void animateHurt();
virtual bool isPickable();
@ -71,8 +71,8 @@ public:
std::wstring getName();
virtual bool interact(std::shared_ptr<Player> player);
virtual void setDamage(int damage);
virtual int getDamage();
virtual void setDamage(float damage);
virtual float getDamage();
virtual void setHurtTime(int hurtTime);
virtual int getHurtTime();
virtual void setHurtDir(int hurtDir);

View file

@ -1,24 +0,0 @@
#include "../../Platform/stdafx.h"
#include "../BossMobPart.h"
#include "BossMob.h"
BossMob::BossMob(Level* level) : Mob(level) {
maxHealth = 100;
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
}
int BossMob::getMaxHealth() { return maxHealth; }
bool BossMob::hurt(std::shared_ptr<BossMobPart> bossMobPart,
DamageSource* source, int damage) {
return hurt(source, damage);
}
bool BossMob::hurt(DamageSource* source, int damage) { return false; }
bool BossMob::reallyHurt(DamageSource* source, int damage) {
return Mob::hurt(source, damage);
}

View file

@ -1,22 +1,8 @@
#pragma once
#include "../Mob.h"
class Level;
class BossMobPart;
class BossMob : public Mob {
protected:
int maxHealth;
class BossMob {
public:
BossMob(Level* level);
virtual int getMaxHealth();
virtual bool hurt(std::shared_ptr<BossMobPart> bossMobPart,
DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, int damage);
protected:
virtual bool reallyHurt(DamageSource* source, int damage);
virtual float getMaxHealth() = 0;
virtual float getHealth() = 0;
virtual std::wstring getAName() = 0;
};

View file

@ -1,5 +1,7 @@
#include "../../Platform/stdafx.h"
#include "../../Util/SharedConstants.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.effect.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.h"
@ -9,19 +11,20 @@
CaveSpider::CaveSpider(Level* level) : Spider(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
this->textureIdx = TN_MOB_CAVE_SPIDER; // 4J was "/mob/cavespider.png";
this->setSize(0.7f, 0.5f);
}
int CaveSpider::getMaxHealth() { return 12; }
void CaveSpider::registerAttributes() {
Spider::registerAttributes();
float CaveSpider::getModelScale() { return .7f; }
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(12);
}
bool CaveSpider::doHurtTarget(std::shared_ptr<Entity> target) {
if (Spider::doHurtTarget(target)) {
if (std::dynamic_pointer_cast<Mob>(target) != NULL) {
if (target->instanceof(eTYPE_LIVINGENTITY)) {
int poisonTime = 0;
if (level->difficulty <= Difficulty::EASY) {
// No poison!
@ -32,7 +35,7 @@ bool CaveSpider::doHurtTarget(std::shared_ptr<Entity> target) {
}
if (poisonTime > 0) {
std::dynamic_pointer_cast<Mob>(target)->addEffect(
std::dynamic_pointer_cast<LivingEntity>(target)->addEffect(
new MobEffectInstance(
MobEffect::poison->id,
poisonTime * SharedConstants::TICKS_PER_SECOND, 0));
@ -44,6 +47,9 @@ bool CaveSpider::doHurtTarget(std::shared_ptr<Entity> target) {
return false;
}
void CaveSpider::finalizeMobSpawn() {
MobGroupData* CaveSpider::finalizeMobSpawn(
MobGroupData* groupData, int extraData /*= 0*/) // 4J Added extraData param
{
// do nothing
return groupData;
}

View file

@ -10,8 +10,12 @@ public:
public:
CaveSpider(Level* level);
virtual int getMaxHealth();
virtual float getModelScale();
protected:
void registerAttributes();
public:
virtual bool doHurtTarget(std::shared_ptr<Entity> target);
void finalizeMobSpawn();
MobGroupData* finalizeMobSpawn(
MobGroupData* groupData,
int extraData = 0); // 4J Added extraData param
};

View file

@ -1,6 +1,8 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/com.mojang.nbt.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.ai.goal.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
#include "../../Headers/net.minecraft.world.phys.h"
#include "../../Headers/net.minecraft.world.level.h"
@ -23,31 +25,32 @@ Chicken::Chicken(Level* level) : Animal(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
setHealth(getMaxHealth());
_init();
this->textureIdx = TN_MOB_CHICKEN; // 4J - was L"/mob/chicken.png";
this->setSize(0.3f, 0.7f); // 4J Changed from 0.4 to 0.7 in 1.8.2
setSize(0.3f, 0.7f); // 4J Changed from 0.4 to 0.7 in 1.8.2
eggTime = random->nextInt(20 * 60 * 5) + 20 * 60 * 5;
float walkSpeed = 0.25f;
goalSelector.addGoal(0, new FloatGoal(this));
goalSelector.addGoal(1, new PanicGoal(this, 0.38f));
goalSelector.addGoal(2, new BreedGoal(this, walkSpeed));
goalSelector.addGoal(
3, new TemptGoal(this, 0.25f, Item::seeds_wheat_Id, false));
goalSelector.addGoal(4, new FollowParentGoal(this, 0.28f));
goalSelector.addGoal(5, new RandomStrollGoal(this, walkSpeed));
goalSelector.addGoal(1, new PanicGoal(this, 1.4));
goalSelector.addGoal(2, new BreedGoal(this, 1.0));
goalSelector.addGoal(3,
new TemptGoal(this, 1.0, Item::seeds_wheat_Id, false));
goalSelector.addGoal(4, new FollowParentGoal(this, 1.1));
goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0));
goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 6));
goalSelector.addGoal(7, new RandomLookAroundGoal(this));
}
bool Chicken::useNewAi() { return true; }
int Chicken::getMaxHealth() { return 4; }
void Chicken::registerAttributes() {
Animal::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(4);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f);
}
void Chicken::aiStep() {
Animal::aiStep();
@ -70,8 +73,8 @@ void Chicken::aiStep() {
if (!isBaby()) {
if (!level->isClientSide && --eggTime <= 0) {
level->playSound(
shared_from_this(), eSoundType_MOB_CHICKENPLOP, 1.0f,
playSound(
eSoundType_MOB_CHICKENPLOP, 1.0f,
(random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
spawnAtLocation(Item::egg->id, 1);
eggTime = random->nextInt(20 * 60 * 5) + 20 * 60 * 5;
@ -87,6 +90,10 @@ int Chicken::getHurtSound() { return eSoundType_MOB_CHICKEN_HURT; }
int Chicken::getDeathSound() { return eSoundType_MOB_CHICKEN_HURT; }
void Chicken::playStepSound(int xt, int yt, int zt, int t) {
playSound(eSoundType_MOB_CHICKEN_STEP, 0.15f, 1);
}
int Chicken::getDeathLoot() { return Item::feather->id; }
void Chicken::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) {
@ -115,7 +122,7 @@ std::shared_ptr<AgableMob> Chicken::getBreedOffspring(
bool Chicken::isFood(std::shared_ptr<ItemInstance> itemInstance) {
return (itemInstance->id == Item::seeds_wheat_Id) ||
(itemInstance->id == Item::netherStalkSeeds_Id) ||
(itemInstance->id == Item::netherwart_seeds_Id) ||
(itemInstance->id == Item::seeds_melon_Id) ||
(itemInstance->id == Item::seeds_pumpkin_Id);
}

View file

@ -22,7 +22,11 @@ private:
public:
Chicken(Level* level);
virtual bool useNewAi();
virtual int getMaxHealth();
protected:
void registerAttributes();
public:
virtual void aiStep();
protected:
@ -30,6 +34,7 @@ protected:
virtual int getAmbientSound();
virtual int getHurtSound();
virtual int getDeathSound();
virtual void playStepSound(int xt, int yt, int zt, int t);
virtual int getDeathLoot();
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);

View file

@ -1,5 +1,6 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/com.mojang.nbt.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.ai.navigation.h"
#include "../../Headers/net.minecraft.world.entity.ai.goal.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
@ -7,6 +8,7 @@
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.entity.player.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.stats.h"
#include "Cow.h"
#include "../../../Minecraft.Client/Textures/Textures.h"
@ -16,28 +18,30 @@ Cow::Cow(Level* level) : Animal(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
registerAttributes();
setHealth(getMaxHealth());
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
this->textureIdx = TN_MOB_COW; // 4J was L"/mob/cow.png";
this->setSize(0.9f, 1.3f);
getNavigation()->setAvoidWater(true);
goalSelector.addGoal(0, new FloatGoal(this));
goalSelector.addGoal(1, new PanicGoal(this, 0.38f));
goalSelector.addGoal(2, new BreedGoal(this, 0.2f));
goalSelector.addGoal(3, new TemptGoal(this, 0.25f, Item::wheat_Id, false));
goalSelector.addGoal(4, new FollowParentGoal(this, 0.25f));
goalSelector.addGoal(5, new RandomStrollGoal(this, 0.2f));
goalSelector.addGoal(1, new PanicGoal(this, 2.0f));
goalSelector.addGoal(2, new BreedGoal(this, 1.0f));
goalSelector.addGoal(3, new TemptGoal(this, 1.25f, Item::wheat_Id, false));
goalSelector.addGoal(4, new FollowParentGoal(this, 1.25f));
goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0f));
goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 6));
goalSelector.addGoal(7, new RandomLookAroundGoal(this));
}
bool Cow::useNewAi() { return true; }
int Cow::getMaxHealth() { return 10; }
void Cow::registerAttributes() {
Animal::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f);
}
int Cow::getAmbientSound() { return eSoundType_MOB_COW_AMBIENT; }
@ -45,6 +49,10 @@ int Cow::getHurtSound() { return eSoundType_MOB_COW_HURT; }
int Cow::getDeathSound() { return eSoundType_MOB_COW_HURT; }
void Cow::playStepSound(int xt, int yt, int zt, int t) {
playSound(eSoundType_MOB_COW_STEP, 0.15f, 1);
}
float Cow::getSoundVolume() { return 0.4f; }
int Cow::getDeathLoot() { return Item::leather->id; }
@ -66,25 +74,27 @@ void Cow::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) {
}
}
bool Cow::interact(std::shared_ptr<Player> player) {
bool Cow::mobInteract(std::shared_ptr<Player> player) {
std::shared_ptr<ItemInstance> item = player->inventory->getSelected();
if (item != NULL && item->id == Item::bucket_empty->id) {
if (item != NULL && item->id == Item::bucket_empty->id &&
!player->abilities.instabuild) {
player->awardStat(GenericStats::cowsMilked(),
GenericStats::param_cowsMilked());
if (--item->count <= 0) {
if (item->count-- == 0) {
player->inventory->setItem(
player->inventory->selected,
std::shared_ptr<ItemInstance>(new ItemInstance(Item::milk)));
std::shared_ptr<ItemInstance>(
new ItemInstance(Item::bucket_milk)));
} else if (!player->inventory->add(std::shared_ptr<ItemInstance>(
new ItemInstance(Item::milk)))) {
player->drop(
std::shared_ptr<ItemInstance>(new ItemInstance(Item::milk)));
new ItemInstance(Item::bucket_milk)))) {
player->drop(std::shared_ptr<ItemInstance>(
new ItemInstance(Item::bucket_milk)));
}
return true;
}
return Animal::interact(player);
return Animal::mobInteract(player);
}
std::shared_ptr<AgableMob> Cow::getBreedOffspring(

View file

@ -13,18 +13,19 @@ public:
public:
Cow(Level* level);
virtual bool useNewAi();
virtual int getMaxHealth();
protected:
virtual void registerAttributes();
virtual int getAmbientSound();
virtual int getHurtSound();
virtual int getDeathSound();
virtual float getSoundVolume();
virtual int getDeathLoot();
virtual void playStepSound(int xt, int yt, int zt, int t);
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
public:
virtual bool interact(std::shared_ptr<Player> player);
virtual bool mobInteract(std::shared_ptr<Player> player);
virtual std::shared_ptr<AgableMob> getBreedOffspring(
std::shared_ptr<AgableMob> target);
};

View file

@ -3,11 +3,13 @@
#include "../../Headers/net.minecraft.world.level.tile.h"
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.ai.goal.h"
#include "../../Headers/net.minecraft.world.entity.ai.goal.target.h"
#include "../../Headers/net.minecraft.world.entity.ai.navigation.h"
#include "../../Headers/net.minecraft.world.entity.animal.h"
#include "../../Headers/net.minecraft.world.entity.player.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.damagesource.h"
#include "../../Stats/GeneralStat.h"
#include "Skeleton.h"
@ -19,38 +21,53 @@
void Creeper::_init() {
swell = 0;
oldSwell = 0;
maxSwell = 30;
explosionRadius = 3;
}
Creeper::Creeper(Level* level) : Monster(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
setHealth(getMaxHealth());
_init();
this->textureIdx = TN_MOB_CREEPER; // 4J was L"/mob/creeper.png";
goalSelector.addGoal(1, new FloatGoal(this));
goalSelector.addGoal(2, new SwellGoal(this));
goalSelector.addGoal(
3, new AvoidPlayerGoal(this, typeid(Ozelot), 6, 0.25f, 0.30f));
goalSelector.addGoal(4, new MeleeAttackGoal(this, 0.25f, false));
goalSelector.addGoal(5, new RandomStrollGoal(this, 0.20f));
3, new AvoidPlayerGoal(this, typeid(Ocelot), 6, 1.0, 1.2));
goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false));
goalSelector.addGoal(5, new RandomStrollGoal(this, 0.8));
goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8));
goalSelector.addGoal(6, new RandomLookAroundGoal(this));
targetSelector.addGoal(
1, new NearestAttackableTargetGoal(this, typeid(Player), 16, 0, true));
1, new NearestAttackableTargetGoal(this, typeid(Player), 0, true));
targetSelector.addGoal(2, new HurtByTargetGoal(this, false));
}
void Creeper::registerAttributes() {
Monster::registerAttributes();
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f);
}
bool Creeper::useNewAi() { return true; }
int Creeper::getMaxHealth() { return 20; }
int Creeper::getMaxFallDistance() {
if (getTarget() == NULL) return 3;
// As long as they survive the fall they should try.
return 3 + (int)(getHealth() - 1);
}
void Creeper::causeFallDamage(float distance) {
Monster::causeFallDamage(distance);
swell += distance * 1.5f;
if (swell > maxSwell - 5) swell = maxSwell - 5;
}
void Creeper::defineSynchedData() {
Monster::defineSynchedData();
@ -63,12 +80,17 @@ void Creeper::addAdditonalSaveData(CompoundTag* entityTag) {
Monster::addAdditonalSaveData(entityTag);
if (entityData->getByte(DATA_IS_POWERED) == 1)
entityTag->putBoolean(L"powered", true);
entityTag->putShort(L"Fuse", (short)maxSwell);
entityTag->putByte(L"ExplosionRadius", (uint8_t)explosionRadius);
}
void Creeper::readAdditionalSaveData(CompoundTag* tag) {
Monster::readAdditionalSaveData(tag);
entityData->set(DATA_IS_POWERED,
(uint8_t)(tag->getBoolean(L"powered") ? 1 : 0));
if (tag->contains(L"Fuse")) maxSwell = tag->getShort(L"Fuse");
if (tag->contains(L"ExplosionRadius"))
explosionRadius = tag->getByte(L"ExplosionRadius");
}
void Creeper::tick() {
@ -76,21 +98,20 @@ void Creeper::tick() {
if (isAlive()) {
int swellDir = getSwellDir();
if (swellDir > 0 && swell == 0) {
level->playSound(shared_from_this(), eSoundType_RANDOM_FUSE, 1,
0.5f);
playSound(eSoundType_RANDOM_FUSE, 1, 0.5f);
}
swell += swellDir;
if (swell < 0) swell = 0;
if (swell >= MAX_SWELL) {
swell = MAX_SWELL;
if (swell >= maxSwell) {
swell = maxSwell;
if (!level->isClientSide) {
bool destroyBlocks =
true; // level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
bool destroyBlocks = level->getGameRules()->getBoolean(
GameRules::RULE_MOBGRIEFING);
if (isPowered())
level->explode(shared_from_this(), x, y, z, 6,
destroyBlocks);
level->explode(shared_from_this(), x, y, z,
explosionRadius * 2, destroyBlocks);
else
level->explode(shared_from_this(), x, y, z, 3,
level->explode(shared_from_this(), x, y, z, explosionRadius,
destroyBlocks);
remove();
}
@ -106,14 +127,20 @@ int Creeper::getDeathSound() { return eSoundType_MOB_CREEPER_DEATH; }
void Creeper::die(DamageSource* source) {
Monster::die(source);
if (std::dynamic_pointer_cast<Skeleton>(source->getEntity()) != NULL) {
spawnAtLocation(Item::record_01_Id + random->nextInt(12), 1);
if (source->getEntity() != NULL &&
source->getEntity()->instanceof(eTYPE_SKELETON)) {
int recordId =
Item::record_01_Id +
random->nextInt(Item::record_12_Id - Item::record_01_Id + 1);
spawnAtLocation(recordId, 1);
}
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(source->getEntity());
if ((std::dynamic_pointer_cast<Arrow>(source->getDirectEntity()) != NULL) &&
(player != NULL)) {
if (source->getDirectEntity() != NULL &&
source->getDirectEntity()->instanceof(eTYPE_ARROW) &&
source->getEntity() != NULL &&
source->getEntity()->instanceof(eTYPE_PLAYER)) {
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(source->getEntity());
player->awardStat(GenericStats::archer(), GenericStats::param_archer());
}
}
@ -123,10 +150,10 @@ bool Creeper::doHurtTarget(std::shared_ptr<Entity> target) { return true; }
bool Creeper::isPowered() { return entityData->getByte(DATA_IS_POWERED) == 1; }
float Creeper::getSwelling(float a) {
return (oldSwell + (swell - oldSwell) * a) / (MAX_SWELL - 2);
return (oldSwell + (swell - oldSwell) * a) / (maxSwell - 2);
}
int Creeper::getDeathLoot() { return Item::sulphur->id; }
int Creeper::getDeathLoot() { return Item::gunpowder_Id; }
int Creeper::getSwellDir() {
return (int)(char)entityData->getByte(DATA_SWELL_DIR);

View file

@ -14,20 +14,26 @@ private:
static const int DATA_SWELL_DIR = 16;
static const int DATA_IS_POWERED = 17;
int swell;
int oldSwell;
static const int MAX_SWELL = 30;
int swell;
int maxSwell;
int explosionRadius;
void _init();
public:
Creeper(Level* level);
protected:
void registerAttributes();
public:
virtual bool useNewAi();
virtual int getMaxHealth();
virtual int getMaxFallDistance();
protected:
virtual void causeFallDamage(float distance);
virtual void defineSynchedData();
public:

View file

@ -15,7 +15,7 @@ DragonFireball::DragonFireball(Level* level) : Fireball(level) {
setSize(5 / 16.0f, 5 / 16.0f);
}
DragonFireball::DragonFireball(Level* level, std::shared_ptr<Mob> mob,
DragonFireball::DragonFireball(Level* level, std::shared_ptr<LivingEntity> mob,
double xa, double ya, double za)
: Fireball(level, mob, xa, ya, za) {
setSize(5 / 16.0f, 5 / 16.0f);
@ -31,14 +31,15 @@ void DragonFireball::onHit(HitResult* res) {
if (!level->isClientSide) {
AABB* aoe = bb->grow(SPLASH_RANGE, SPLASH_RANGE / 2, SPLASH_RANGE);
std::vector<std::shared_ptr<Entity> >* entitiesOfClass =
level->getEntitiesOfClass(typeid(Mob), aoe);
level->getEntitiesOfClass(typeid(LivingEntity), aoe);
if (entitiesOfClass != NULL && !entitiesOfClass->empty()) {
// for (Entity e : entitiesOfClass)
for (AUTO_VAR(it, entitiesOfClass->begin());
it != entitiesOfClass->end(); ++it) {
// std::shared_ptr<Entity> e = *it;
std::shared_ptr<Mob> e = std::dynamic_pointer_cast<Mob>(*it);
// shared_ptr<Entity> e = *it;
std::shared_ptr<LivingEntity> e =
std::dynamic_pointer_cast<LivingEntity>(*it);
double dist = distanceToSqr(e);
if (dist < SPLASH_RANGE_SQ) {
double scale = 1.0 - (sqrt(dist) / SPLASH_RANGE);
@ -60,12 +61,10 @@ void DragonFireball::onHit(HitResult* res) {
bool DragonFireball::isPickable() { return false; }
bool DragonFireball::hurt(DamageSource* source, int damage) { return false; }
bool DragonFireball::shouldBurn() { return false; }
int DragonFireball::getIcon() { return 15 + 14 * 16; }
bool DragonFireball::hurt(DamageSource* source, float damage) { return false; }
ePARTICLE_TYPE DragonFireball::getTrailParticleType() {
return eParticleType_dragonbreath;
}
}
bool DragonFireball::shouldBurn() { return false; }

View file

@ -17,8 +17,8 @@ private:
public:
DragonFireball(Level* level);
DragonFireball(Level* level, std::shared_ptr<Mob> mob, double xa, double ya,
double za);
DragonFireball(Level* level, std::shared_ptr<LivingEntity> mob, double xa,
double ya, double za);
DragonFireball(Level* level, double x, double y, double z, double xa,
double ya, double za);
@ -27,12 +27,11 @@ protected:
public:
virtual bool isPickable();
virtual bool hurt(DamageSource* source, int damage);
virtual bool shouldBurn();
virtual int getIcon();
virtual bool hurt(DamageSource* source, float damage);
protected:
// 4J Added TU9
virtual ePARTICLE_TYPE getTrailParticleType();
virtual bool shouldBurn();
};

View file

@ -50,7 +50,7 @@ void EnderCrystal::tick() {
int yt = Mth::floor(y);
int zt = Mth::floor(z);
if (level->getTile(xt, yt, zt) != Tile::fire_Id) {
level->setTile(xt, yt, zt, Tile::fire_Id);
level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id);
}
}
}
@ -63,13 +63,13 @@ float EnderCrystal::getShadowHeightOffs() { return 0; }
bool EnderCrystal::isPickable() { return true; }
bool EnderCrystal::hurt(DamageSource* source, int damage) {
bool EnderCrystal::hurt(DamageSource* source, float damage) {
if (isInvulnerable()) return false;
// 4J-PB - if the owner of the source is the enderdragon, then ignore it
// (where the dragon's fireball hits an endercrystal)
std::shared_ptr<EnderDragon> sourceIsDragon =
std::dynamic_pointer_cast<EnderDragon>(source->getEntity());
if (sourceIsDragon != NULL) {
if (source->getEntity() != NULL &&
source->getEntity()->instanceof(eTYPE_ENDERDRAGON)) {
return false;
}

View file

@ -38,5 +38,5 @@ protected:
public:
virtual float getShadowHeightOffs();
virtual bool isPickable();
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
};

View file

@ -2,7 +2,9 @@
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.boss.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.entity.projectile.h"
#include "../../Headers/net.minecraft.world.phys.h"
#include "../../Headers/net.minecraft.world.damagesource.h"
@ -48,10 +50,8 @@ void EnderDragon::_init() {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
setHealth(getMaxHealth());
xTarget = yTarget = zTarget = 0.0;
posPointer = -1;
@ -86,33 +86,9 @@ void EnderDragon::_init() {
m_currentPath = NULL;
}
EnderDragon::EnderDragon(Level* level) : BossMob(level) {
EnderDragon::EnderDragon(Level* level) : Mob(level) {
_init();
head = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"head", 6, 6));
neck = std::shared_ptr<BossMobPart>(
new BossMobPart(this, L"neck", 6, 6)); // 4J Added
body = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"body", 8, 8));
tail1 = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"tail", 4, 4));
tail2 = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"tail", 4, 4));
tail3 = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"tail", 4, 4));
wing1 = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"wing", 4, 4));
wing2 = std::shared_ptr<BossMobPart>(new BossMobPart(this, L"wing", 4, 4));
subEntities.push_back(head);
subEntities.push_back(neck); // 4J Added
subEntities.push_back(body);
subEntities.push_back(tail1);
subEntities.push_back(tail2);
subEntities.push_back(tail3);
subEntities.push_back(wing1);
subEntities.push_back(wing2);
maxHealth = 200;
setHealth(maxHealth);
this->textureIdx =
TN_MOB_ENDERDRAGON; // 4J was "/mob/enderdragon/ender.png";
setSize(16, 8);
noPhysics = true;
@ -125,6 +101,44 @@ EnderDragon::EnderDragon(Level* level) : BossMob(level) {
noCulling = true;
}
// 4J - split off from ctor so we can use shared_from_this()
void EnderDragon::AddParts() {
head = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"head",
6, 6));
neck = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"neck",
6,
6)); // 4J Added
body = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"body",
8, 8));
tail1 = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"tail",
4, 4));
tail2 = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"tail",
4, 4));
tail3 = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"tail",
4, 4));
wing1 = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"wing",
4, 4));
wing2 = std::shared_ptr<MultiEntityMobPart>(new MultiEntityMobPart(
std::dynamic_pointer_cast<MultiEntityMob>(shared_from_this()), L"wing",
4, 4));
subEntities.push_back(head);
subEntities.push_back(neck); // 4J Added
subEntities.push_back(body);
subEntities.push_back(tail1);
subEntities.push_back(tail2);
subEntities.push_back(tail3);
subEntities.push_back(wing1);
subEntities.push_back(wing2);
}
EnderDragon::~EnderDragon() {
if (m_nodes->data != NULL) {
for (unsigned int i = 0; i < m_nodes->length; ++i) {
@ -136,10 +150,14 @@ EnderDragon::~EnderDragon() {
if (m_currentPath != NULL) delete m_currentPath;
}
void EnderDragon::defineSynchedData() {
BossMob::defineSynchedData();
void EnderDragon::registerAttributes() {
Mob::registerAttributes();
entityData->define(DATA_ID_SYNCHED_HEALTH, maxHealth);
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(200);
}
void EnderDragon::defineSynchedData() {
Mob::defineSynchedData();
// 4J Added for new dragon behaviour
entityData->define(DATA_ID_SYNCHED_ACTION,
@ -147,7 +165,7 @@ void EnderDragon::defineSynchedData() {
}
void EnderDragon::getLatencyPos(doubleArray result, int step, float a) {
if (health <= 0) {
if (getHealth() <= 0) {
a = 0;
}
@ -173,21 +191,20 @@ void EnderDragon::getLatencyPos(doubleArray result, int step, float a) {
}
void EnderDragon::aiStep() {
if (!level->isClientSide) {
entityData->set(DATA_ID_SYNCHED_HEALTH, health);
} else {
if (level->isClientSide) {
// 4J Stu - If saved when dead we need to make sure that the actual
// health is updated correctly on the client Fix for TU9: Content:
// Gameplay: Enderdragon respawns after loading game which was
// previously saved at point of hes death
health = getSynchedHealth();
setHealth(getHealth());
float flap = Mth::cos(flapTime * PI * 2);
float oldFlap = Mth::cos(oFlapTime * PI * 2);
if (oldFlap <= -0.3f && flap >= -0.3f) {
level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_MOVE, 1,
0.8f + random->nextFloat() * .3f, 100.0f);
0.8f + random->nextFloat() * .3f, false,
100.0f);
}
// play a growl every now and then
if (!(getSynchedAction() == e_EnderdragonAction_Sitting_Flaming ||
@ -197,7 +214,7 @@ void EnderDragon::aiStep() {
if (m_iGrowlTimer < 0) {
level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL,
0.5f, 0.8f + random->nextFloat() * .3f,
100.0f);
false, 100.0f);
m_iGrowlTimer = 200 + (random->nextInt(200));
}
}
@ -205,7 +222,7 @@ void EnderDragon::aiStep() {
oFlapTime = flapTime;
if (health <= 0) {
if (getHealth() <= 0) {
// level.addParticle("explode", x + random.nextFloat() *
// bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight,
// z + random.nextFloat() * bbWidth * 2 - bbWidth, 0, 0, 0);
@ -352,7 +369,7 @@ void EnderDragon::aiStep() {
// AP - changed this to use playLocalSound because no sound could be
// heard with playSound (cos it's a stub function)
level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL,
0.5f, 0.8f + random->nextFloat() * .3f,
0.5f, 0.8f + random->nextFloat() * .3f, false,
100.0f);
}
} else {
@ -447,10 +464,10 @@ void EnderDragon::aiStep() {
for (AUTO_VAR(it, targets->begin()); it != targets->end();
++it) {
std::shared_ptr<Mob> e =
std::dynamic_pointer_cast<Mob>(*it);
if (e != NULL) {
if ((*it)->instanceof(eTYPE_LIVINGENTITY)) {
// app.DebugPrintf("Attacking entity with acid\n");
std::shared_ptr<LivingEntity> e =
std::dynamic_pointer_cast<LivingEntity>(*it);
e->hurt(DamageSource::dragonbreath, 2);
}
}
@ -685,7 +702,7 @@ void EnderDragon::aiStep() {
// Curls/straightens the tail
for (int i = 0; i < 3; i++) {
std::shared_ptr<BossMobPart> part = nullptr;
std::shared_ptr<MultiEntityMobPart> part = nullptr;
if (i == 0) part = tail1;
if (i == 1) part = tail2;
@ -782,12 +799,12 @@ void EnderDragon::checkCrystals() {
if (nearestCrystal != NULL) {
if (nearestCrystal->removed) {
if (!level->isClientSide) {
hurt(head, DamageSource::explosion, 10);
hurt(head, DamageSource::explosion(NULL), 10);
}
nearestCrystal = nullptr;
} else if (tickCount % 10 == 0) {
if (health < maxHealth) health++;
if (getHealth() < getMaxHealth()) setHealth(getHealth() + 1);
}
}
@ -836,9 +853,10 @@ void EnderDragon::knockBack(std::vector<std::shared_ptr<Entity> >* entities) {
// for (Entity e : entities)
for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) {
std::shared_ptr<Mob> e = std::dynamic_pointer_cast<Mob>(*it);
if (e != NULL) //(e instanceof Mob)
if ((*it)->instanceof(eTYPE_LIVINGENTITY)) //(e instanceof Mob)
{
std::shared_ptr<LivingEntity> e =
std::dynamic_pointer_cast<LivingEntity>(*it);
double xd = e->x - xm;
double zd = e->z - zm;
double dd = xd * xd + zd * zd;
@ -850,12 +868,13 @@ void EnderDragon::knockBack(std::vector<std::shared_ptr<Entity> >* entities) {
void EnderDragon::hurt(std::vector<std::shared_ptr<Entity> >* entities) {
// for (int i = 0; i < entities->size(); i++)
for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) {
std::shared_ptr<Mob> e =
std::dynamic_pointer_cast<Mob>(*it); // entities.get(i);
if (e != NULL) //(e instanceof Mob)
if ((*it)->instanceof(eTYPE_LIVINGENTITY)) //(e instanceof Mob)
{
std::shared_ptr<LivingEntity> e =
std::dynamic_pointer_cast<LivingEntity>(
*it); // entities.get(i);
DamageSource* damageSource = DamageSource::mobAttack(
std::dynamic_pointer_cast<Mob>(shared_from_this()));
std::dynamic_pointer_cast<LivingEntity>(shared_from_this()));
e->hurt(damageSource, 10);
delete damageSource;
}
@ -919,7 +938,8 @@ void EnderDragon::findNewTarget() {
// setSynchedAction(e_EnderdragonAction_Sitting_Flaming);
// #if PRINT_DRAGON_STATE_CHANGE_MESSAGES
// app.DebugPrintf("Dragon action is now:
//SittingFlaming\n"); #endif m_actionTicks = FLAME_TICKS;
// SittingFlaming\n"); #endif m_actionTicks =
// FLAME_TICKS;
m_flameAttacks = 0;
setSynchedAction(e_EnderdragonAction_Sitting_Scanning);
@ -1066,12 +1086,13 @@ bool EnderDragon::checkWalls(AABB* bb) {
int t = level->getTile(x, y, z);
// 4J Stu - Don't remove fire
if (t == 0 || t == Tile::fire_Id) {
} else if (t == Tile::obsidian_Id || t == Tile::whiteStone_Id ||
t == Tile::unbreakable_Id) {
} else if (t == Tile::obsidian_Id || t == Tile::endStone_Id ||
t == Tile::unbreakable_Id ||
!level->getGameRules()->getBoolean(
GameRules::RULE_MOBGRIEFING)) {
hitWall = true;
} else {
destroyedTile = true;
level->setTile(x, y, z, 0);
destroyedTile = level->removeTile(x, y, z) || destroyedTile;
}
}
}
@ -1087,9 +1108,9 @@ bool EnderDragon::checkWalls(AABB* bb) {
return hitWall;
}
bool EnderDragon::hurt(std::shared_ptr<BossMobPart> bossMobPart,
DamageSource* source, int damage) {
if (bossMobPart != head) {
bool EnderDragon::hurt(std::shared_ptr<MultiEntityMobPart> MultiEntityMobPart,
DamageSource* source, float damage) {
if (MultiEntityMobPart != head) {
damage = damage / 4 + 1;
}
@ -1102,18 +1123,19 @@ bool EnderDragon::hurt(std::shared_ptr<BossMobPart> bossMobPart,
// zTarget = z - cc1 * 5 + (random->nextFloat() - 0.5f) * 2;
// attackTarget = NULL;
if (source == DamageSource::explosion ||
(std::dynamic_pointer_cast<Player>(source->getEntity()) != NULL)) {
int healthBefore = health;
if (source->getEntity() != NULL &&
source->getEntity()->instanceof(eTYPE_PLAYER) ||
source->isExplosion()) {
int healthBefore = getHealth();
reallyHurt(source, damage);
// if(!level->isClientSide) app.DebugPrintf("Health is now %d\n",
// health);
if (health <= 0 &&
if (getHealth() <= 0 &&
!(getSynchedAction() == e_EnderdragonAction_Sitting_Flaming ||
getSynchedAction() == e_EnderdragonAction_Sitting_Scanning ||
getSynchedAction() == e_EnderdragonAction_Sitting_Attacking)) {
health = 1;
setHealth(1);
if (setSynchedAction(e_EnderdragonAction_LandingApproach)) {
if (m_currentPath != NULL) {
@ -1132,7 +1154,7 @@ bool EnderDragon::hurt(std::shared_ptr<BossMobPart> bossMobPart,
if (getSynchedAction() == e_EnderdragonAction_Sitting_Flaming ||
getSynchedAction() == e_EnderdragonAction_Sitting_Scanning ||
getSynchedAction() == e_EnderdragonAction_Sitting_Attacking) {
m_sittingDamageReceived += healthBefore - health;
m_sittingDamageReceived += healthBefore - getHealth();
if (m_sittingDamageReceived >
(SITTING_ALLOWED_DAMAGE_PERCENTAGE * getMaxHealth())) {
@ -1148,11 +1170,17 @@ bool EnderDragon::hurt(std::shared_ptr<BossMobPart> bossMobPart,
return true;
}
bool EnderDragon::hurt(DamageSource* source, float damage) { return false; }
bool EnderDragon::reallyHurt(DamageSource* source, float damage) {
return Mob::hurt(source, damage);
}
void EnderDragon::tickDeath() {
if (getSynchedAction() != e_EnderdragonAction_Sitting_Flaming &&
getSynchedAction() != e_EnderdragonAction_Sitting_Scanning &&
getSynchedAction() != e_EnderdragonAction_Sitting_Attacking) {
if (!level->isClientSide) health = 1;
if (!level->isClientSide) setHealth(1);
return;
}
@ -1175,10 +1203,8 @@ void EnderDragon::tickDeath() {
}
}
if (dragonDeathTime == 1) {
// level->globalLevelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int) x,
// (int) y, (int) z, 0);
level->levelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int)x, (int)y,
(int)z, 0);
level->globalLevelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int)x,
(int)y, (int)z, 0);
}
}
move(0, 0.1f, 0);
@ -1224,15 +1250,18 @@ void EnderDragon::spawnExitPortal(int x, int z) {
if (yy < y) {
if (d > r - 1 - 0.5) {
} else {
level->setTile(xx, yy, zz, Tile::unbreakable_Id);
level->setTileAndUpdate(xx, yy, zz,
Tile::unbreakable_Id);
}
} else if (yy > y) {
level->setTile(xx, yy, zz, 0);
level->setTileAndUpdate(xx, yy, zz, 0);
} else {
if (d > r - 1 - 0.5) {
level->setTile(xx, yy, zz, Tile::unbreakable_Id);
level->setTileAndUpdate(xx, yy, zz,
Tile::unbreakable_Id);
} else {
level->setTile(xx, yy, zz, Tile::endPortalTile_Id);
level->setTileAndUpdate(xx, yy, zz,
Tile::endPortalTile_Id);
}
}
}
@ -1240,15 +1269,15 @@ void EnderDragon::spawnExitPortal(int x, int z) {
}
}
level->setTile(x, y + 0, z, Tile::unbreakable_Id);
level->setTile(x, y + 1, z, Tile::unbreakable_Id);
level->setTile(x, y + 2, z, Tile::unbreakable_Id);
level->setTile(x - 1, y + 2, z, Tile::torch_Id);
level->setTile(x + 1, y + 2, z, Tile::torch_Id);
level->setTile(x, y + 2, z - 1, Tile::torch_Id);
level->setTile(x, y + 2, z + 1, Tile::torch_Id);
level->setTile(x, y + 3, z, Tile::unbreakable_Id);
level->setTile(x, y + 4, z, Tile::dragonEgg_Id);
level->setTileAndUpdate(x, y + 0, z, Tile::unbreakable_Id);
level->setTileAndUpdate(x, y + 1, z, Tile::unbreakable_Id);
level->setTileAndUpdate(x, y + 2, z, Tile::unbreakable_Id);
level->setTileAndUpdate(x - 1, y + 2, z, Tile::torch_Id);
level->setTileAndUpdate(x + 1, y + 2, z, Tile::torch_Id);
level->setTileAndUpdate(x, y + 2, z - 1, Tile::torch_Id);
level->setTileAndUpdate(x, y + 2, z + 1, Tile::torch_Id);
level->setTileAndUpdate(x, y + 3, z, Tile::unbreakable_Id);
level->setTileAndUpdate(x, y + 4, z, Tile::dragonEgg_Id);
// 4J-PB - The podium can be floating with nothing under it, so put some
// whiteStone under it if this is the case
@ -1256,7 +1285,7 @@ void EnderDragon::spawnExitPortal(int x, int z) {
for (int xx = x - (r - 1); xx <= x + (r - 1); xx++) {
for (int zz = z - (r - 1); zz <= z + (r - 1); zz++) {
if (level->isEmptyTile(xx, yy, zz)) {
level->setTile(xx, yy, zz, Tile::whiteStone_Id);
level->setTileAndUpdate(xx, yy, zz, Tile::endStone_Id);
}
}
}
@ -1273,14 +1302,18 @@ std::vector<std::shared_ptr<Entity> >* EnderDragon::getSubEntities() {
bool EnderDragon::isPickable() { return false; }
// Fix for TU9 Enderdragon sound hits being the player sound hits - moved this
// forward from later version
int EnderDragon::getHurtSound() { return eSoundType_MOB_ENDERDRAGON_HIT; }
Level* EnderDragon::getLevel() { return level; }
int EnderDragon::getSynchedHealth() {
return entityData->getInteger(DATA_ID_SYNCHED_HEALTH);
int EnderDragon::getAmbientSound() {
return eSoundType_MOB_ENDERDRAGON_GROWL; //"mob.enderdragon.growl";
}
int EnderDragon::getHurtSound() {
return eSoundType_MOB_ENDERDRAGON_HIT; //"mob.enderdragon.hit";
}
float EnderDragon::getSoundVolume() { return 5; }
// 4J Added for new dragon behaviour
bool EnderDragon::setSynchedAction(EEnderdragonAction action,
bool force /*= false*/) {
@ -1411,7 +1444,8 @@ void EnderDragon::handleCrystalDestroyed(DamageSource* source) {
app.DebugPrintf("Dragon action is now: LandingApproach\n");
#endif
}
} else if (std::dynamic_pointer_cast<Player>(source->getEntity()) != NULL) {
} else if (source->getEntity() != NULL &&
source->getEntity()->instanceof(eTYPE_PLAYER)) {
if (setSynchedAction(e_EnderdragonAction_StrafePlayer)) {
attackTarget =
std::dynamic_pointer_cast<Player>(source->getEntity());
@ -1696,7 +1730,7 @@ void EnderDragon::addAdditonalSaveData(CompoundTag* entityTag) {
entityTag->putShort(L"RemainingCrystals", m_remainingCrystalsCount);
entityTag->putInt(L"DragonState", (int)getSynchedAction());
BossMob::addAdditonalSaveData(entityTag);
Mob::addAdditonalSaveData(entityTag);
}
void EnderDragon::readAdditionalSaveData(CompoundTag* tag) {
@ -1708,7 +1742,7 @@ void EnderDragon::readAdditionalSaveData(CompoundTag* tag) {
if (tag->contains(L"DragonState"))
setSynchedAction((EEnderdragonAction)tag->getInt(L"DragonState"), true);
BossMob::readAdditionalSaveData(tag);
Mob::readAdditionalSaveData(tag);
}
float EnderDragon::getTilt(float a) {

View file

@ -1,21 +1,23 @@
#pragma once
#include "BossMob.h"
#include "MultiEntityMob.h"
#include "../Enemy.h"
class BossMobPart;
class MultiEntityMobPart;
class EnderCrystal;
class Node;
class BinaryHeap;
class Path;
class EnderDragon : public BossMob {
class EnderDragon : public Mob,
public BossMob,
public MultiEntityMob,
public Enemy {
public:
eINSTANCEOF GetType() { return eTYPE_ENDERDRAGON; };
static Entity* create(Level* level) { return new EnderDragon(level); }
private:
static const int DATA_ID_SYNCHED_HEALTH = 16;
// 4J Added for new behaviours
static const int DATA_ID_SYNCHED_ACTION = 17;
@ -28,16 +30,16 @@ public:
double positions[positionsLength][3];
int posPointer;
// BossMobPart[] subEntities;
// MultiEntityMobPart[] subEntities;
std::vector<std::shared_ptr<Entity> > subEntities;
std::shared_ptr<BossMobPart> head;
std::shared_ptr<BossMobPart> neck; // 4J Added
std::shared_ptr<BossMobPart> body;
std::shared_ptr<BossMobPart> tail1;
std::shared_ptr<BossMobPart> tail2;
std::shared_ptr<BossMobPart> tail3;
std::shared_ptr<BossMobPart> wing1;
std::shared_ptr<BossMobPart> wing2;
std::shared_ptr<MultiEntityMobPart> head;
std::shared_ptr<MultiEntityMobPart> neck; // 4J Added
std::shared_ptr<MultiEntityMobPart> body;
std::shared_ptr<MultiEntityMobPart> tail1;
std::shared_ptr<MultiEntityMobPart> tail2;
std::shared_ptr<MultiEntityMobPart> tail3;
std::shared_ptr<MultiEntityMobPart> wing1;
std::shared_ptr<MultiEntityMobPart> wing2;
float oFlapTime;
float flapTime;
@ -113,9 +115,11 @@ private:
public:
EnderDragon(Level* level);
void AddParts();
virtual ~EnderDragon();
protected:
virtual void registerAttributes();
virtual void defineSynchedData();
public:
@ -123,7 +127,7 @@ public:
virtual void aiStep();
private:
using BossMob::hurt;
using MultiEntityMob::hurt;
void checkCrystals();
void checkAttack();
@ -134,10 +138,12 @@ private:
bool checkWalls(AABB* bb);
public:
virtual bool hurt(std::shared_ptr<BossMobPart> bossMobPart,
DamageSource* source, int damage);
virtual bool hurt(std::shared_ptr<MultiEntityMobPart> MultiEntityMobPart,
DamageSource* source, float damage);
virtual bool hurt(DamageSource* source, float damage);
protected:
virtual bool reallyHurt(DamageSource* source, float damage);
virtual void tickDeath();
private:
@ -145,12 +151,16 @@ private:
protected:
virtual void checkDespawn();
virtual int getHurtSound();
public:
virtual std::vector<std::shared_ptr<Entity> >* getSubEntities();
virtual bool isPickable();
virtual int getSynchedHealth();
Level* getLevel();
protected:
int getAmbientSound();
int getHurtSound();
float getSoundVolume();
private:
// 4J added for new dragon behaviour
@ -179,4 +189,8 @@ public:
double getHeadPartYRotDiff(int partIndex, doubleArray bodyPos,
doubleArray partPos);
Vec3* getHeadLookVector(float a);
virtual std::wstring getAName() { return app.GetString(IDS_ENDERDRAGON); };
virtual float getHealth() { return LivingEntity::getHealth(); };
virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); };
};

View file

@ -1,6 +1,8 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/net.minecraft.world.entity.player.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.level.tile.h"
@ -10,6 +12,11 @@
#include "../../../Minecraft.Client/Textures/Textures.h"
#include "EnderMan.h"
AttributeModifier* EnderMan::SPEED_MODIFIER_ATTACKING =
(new AttributeModifier(eModifierId_MOB_ENDERMAN_ATTACKSPEED, 6.2f,
AttributeModifier::OPERATION_ADDITION))
->setSerialize(false);
bool EnderMan::MAY_TAKE[256];
void EnderMan::staticCtor() {
@ -20,8 +27,8 @@ void EnderMan::staticCtor() {
MAY_TAKE[Tile::gravel_Id] = true;
MAY_TAKE[Tile::flower_Id] = true;
MAY_TAKE[Tile::rose_Id] = true;
MAY_TAKE[Tile::mushroom1_Id] = true;
MAY_TAKE[Tile::mushroom2_Id] = true;
MAY_TAKE[Tile::mushroom_brown_Id] = true;
MAY_TAKE[Tile::mushroom_red_Id] = true;
MAY_TAKE[Tile::tnt_Id] = true;
MAY_TAKE[Tile::cactus_Id] = true;
MAY_TAKE[Tile::clay_Id] = true;
@ -35,25 +42,27 @@ EnderMan::EnderMan(Level* level) : Monster(level) {
// ensure that the derived version of the function is called Brought forward
// from 1.2.3
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
setHealth(getMaxHealth());
// 4J initialisors
teleportTime = 0;
aggroTime = 0;
lastAttackTarget = nullptr;
aggroedByPlayer = false;
this->textureIdx = TN_MOB_ENDERMAN; // 4J was "/mob/enderman.png";
runSpeed = 0.2f;
attackDamage = 7;
setSize(0.6f, 2.9f);
footSize = 1;
}
int EnderMan::getMaxHealth() { return 40; }
void EnderMan::registerAttributes() {
Monster::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(40);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f);
getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(7);
}
// Brought forward from 1.2.3
void EnderMan::defineSynchedData() {
Monster::defineSynchedData();
@ -85,6 +94,10 @@ std::shared_ptr<Entity> EnderMan::findAttackTarget() {
level->getNearestAttackablePlayer(shared_from_this(), 64);
if (player != NULL) {
if (isLookingAtMe(player)) {
aggroedByPlayer = true;
if (aggroTime == 0)
level->playEntitySound(player, eSoundType_MOB_ENDERMAN_STARE, 1,
1);
if (aggroTime++ == 5) {
aggroTime = 0;
setCreepy(true);
@ -116,42 +129,53 @@ bool EnderMan::isLookingAtMe(std::shared_ptr<Player> player) {
}
void EnderMan::aiStep() {
if (this->isInWaterOrRain()) hurt(DamageSource::drown, 1);
if (isInWaterOrRain()) hurt(DamageSource::drown, 1);
runSpeed = attackTarget != NULL ? 6.5f : 0.3f;
if (lastAttackTarget != attackTarget) {
AttributeInstance* speed =
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
speed->removeModifier(SPEED_MODIFIER_ATTACKING);
if (attackTarget != NULL) {
speed->addModifier(
new AttributeModifier(*SPEED_MODIFIER_ATTACKING));
}
}
lastAttackTarget = attackTarget;
if (!level->isClientSide) {
if (getCarryingTile() == 0) {
if (random->nextInt(20) == 0) {
int xt = Mth::floor(x - 2 + random->nextDouble() * 4);
int yt = Mth::floor(y + random->nextDouble() * 3);
int zt = Mth::floor(z - 2 + random->nextDouble() * 4);
int t = level->getTile(xt, yt, zt);
// if (t > 0 && Tile::tiles[t]->isCubeShaped())
if (EnderMan::MAY_TAKE[t]) // 4J - Brought forward from 1.2.3
{
setCarryingTile(level->getTile(xt, yt, zt));
setCarryingData(level->getData(xt, yt, zt));
level->setTile(xt, yt, zt, 0);
if (level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) {
if (getCarryingTile() == 0) {
if (random->nextInt(20) == 0) {
int xt = Mth::floor(x - 2 + random->nextDouble() * 4);
int yt = Mth::floor(y + random->nextDouble() * 3);
int zt = Mth::floor(z - 2 + random->nextDouble() * 4);
int t = level->getTile(xt, yt, zt);
if (MAY_TAKE[t]) {
setCarryingTile(level->getTile(xt, yt, zt));
setCarryingData(level->getData(xt, yt, zt));
level->setTileAndUpdate(xt, yt, zt, 0);
}
}
}
} else {
if (random->nextInt(2000) == 0) {
int xt = Mth::floor(x - 1 + random->nextDouble() * 2);
int yt = Mth::floor(y + random->nextDouble() * 2);
int zt = Mth::floor(z - 1 + random->nextDouble() * 2);
int t = level->getTile(xt, yt, zt);
int bt = level->getTile(xt, yt - 1, zt);
if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped()) {
level->setTileAndData(xt, yt, zt, getCarryingTile(),
getCarryingData());
setCarryingTile(0);
} else {
if (random->nextInt(2000) == 0) {
int xt = Mth::floor(x - 1 + random->nextDouble() * 2);
int yt = Mth::floor(y + random->nextDouble() * 2);
int zt = Mth::floor(z - 1 + random->nextDouble() * 2);
int t = level->getTile(xt, yt, zt);
int bt = level->getTile(xt, yt - 1, zt);
if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped()) {
level->setTileAndData(xt, yt, zt, getCarryingTile(),
getCarryingData(),
Tile::UPDATE_ALL);
setCarryingTile(0);
}
}
}
}
}
// 4J - Brought forward particles from 1.2.3
for (int i = 0; i < 2; i++) {
level->addParticle(
eParticleType_ender, x + (random->nextDouble() - 0.5) * bbWidth,
@ -164,34 +188,38 @@ void EnderMan::aiStep() {
if (level->isDay() && !level->isClientSide) {
float br = getBrightness(1);
if (br > 0.5f) {
if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) &&
if (level->canSeeSky(Mth::floor(x), (int)floor(y + 0.5),
Mth::floor(z)) &&
random->nextFloat() * 30 < (br - 0.4f) * 2) {
// 4J - Brought forward behaviour change from 1.2.3
// onFire = 20 * 15;
attackTarget = nullptr;
setCreepy(false);
aggroedByPlayer = false;
teleport();
}
}
}
// 4J Brought forward behaviour change from 1.2.3
if (isInWaterOrRain() || isOnFire()) {
attackTarget = nullptr;
setCreepy(false);
aggroedByPlayer = false;
teleport();
}
if (isCreepy() && !aggroedByPlayer && random->nextInt(100) == 0) {
setCreepy(false);
}
jumping = false;
if (attackTarget != NULL) {
this->lookAt(attackTarget, 100, 100);
lookAt(attackTarget, 100, 100);
}
if (!level->isClientSide && isAlive()) {
if (attackTarget != NULL) {
if (std::dynamic_pointer_cast<Player>(attackTarget) != NULL &&
if (attackTarget->instanceof(eTYPE_PLAYER) &&
isLookingAtMe(
std::dynamic_pointer_cast<Player>(attackTarget))) {
xxa = yya = 0;
runSpeed = 0;
if (attackTarget->distanceToSqr(shared_from_this()) < 4 * 4) {
teleport();
}
@ -278,15 +306,10 @@ bool EnderMan::teleport(double xx, double yy, double zz) {
double _z =
zo + (z - zo) * d + (random->nextDouble() - 0.5) * bbWidth * 2;
// 4J - Brought forward particle change from 1.2.3
// level->addParticle(eParticleType_largesmoke, _x, _y, _z, xa, ya,
// za);
level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za);
}
// 4J - moved sounds forward from 1.2.3
level->playSound(xo, yo, zo, eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
level->playSound(shared_from_this(), eSoundType_MOB_ENDERMEN_PORTAL, 1,
1);
playSound(eSoundType_MOB_ENDERMEN_PORTAL, 1, 1);
return true;
} else {
setPos(xo, yo, zo);
@ -295,19 +318,13 @@ bool EnderMan::teleport(double xx, double yy, double zz) {
}
int EnderMan::getAmbientSound() {
// 4J - brought sound change forward from 1.2.3
return eSoundType_MOB_ENDERMEN_IDLE;
return isCreepy() ? eSoundType_MOB_ENDERMAN_SCREAM
: eSoundType_MOB_ENDERMEN_IDLE;
}
int EnderMan::getHurtSound() {
// 4J - brought sound change forward from 1.2.3
return eSoundType_MOB_ENDERMEN_HIT;
}
int EnderMan::getHurtSound() { return eSoundType_MOB_ENDERMEN_HIT; }
int EnderMan::getDeathSound() {
// 4J - brought sound change forward from 1.2.3
return eSoundType_MOB_ENDERMEN_DEATH;
}
int EnderMan::getDeathSound() { return eSoundType_MOB_ENDERMEN_DEATH; }
int EnderMan::getDeathLoot() { return Item::enderPearl_Id; }
@ -336,10 +353,21 @@ int EnderMan::getCarryingData() {
return entityData->getByte(DATA_CARRY_ITEM_DATA);
}
bool EnderMan::hurt(DamageSource* source, int damage) {
bool EnderMan::hurt(DamageSource* source, float damage) {
if (isInvulnerable()) return false;
setCreepy(true);
if (dynamic_cast<EntityDamageSource*>(source) != NULL &&
source->getEntity()->instanceof(eTYPE_PLAYER)) {
aggroedByPlayer = true;
}
if (dynamic_cast<IndirectEntityDamageSource*>(source) != NULL) {
aggroedByPlayer = false;
for (int i = 0; i < 64; i++) {
if (teleport()) return true;
if (teleport()) {
return true;
}
}
return false;
}
@ -350,4 +378,4 @@ bool EnderMan::isCreepy() { return entityData->getByte(DATA_CREEPY) > 0; }
void EnderMan::setCreepy(bool creepy) {
entityData->set(DATA_CREEPY, (uint8_t)(creepy ? 1 : 0));
}
}

View file

@ -11,6 +11,8 @@ public:
static void staticCtor();
private:
static AttributeModifier* SPEED_MODIFIER_ATTACKING;
static bool MAY_TAKE[256];
static const int DATA_CARRY_ITEM_ID = 16;
@ -20,13 +22,14 @@ private:
private:
int teleportTime;
int aggroTime;
std::shared_ptr<Entity> lastAttackTarget;
bool aggroedByPlayer;
public:
EnderMan(Level* level);
virtual int getMaxHealth();
protected:
virtual void registerAttributes();
virtual void defineSynchedData();
public:
@ -54,12 +57,11 @@ protected:
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
public:
// 4J Brought forward from 1.2.3 to help fix Enderman behaviour
void setCarryingTile(int carryingTile);
int getCarryingTile();
void setCarryingData(int carryingData);
int getCarryingData();
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
bool isCreepy();
void setCreepy(bool creepy);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,343 @@
#pragma once
#include "Animal.h"
#include "../../Headers/net.minecraft.world.ContainerListener.h"
#include "MobGroupData.h"
#include "../EntitySelector.h"
class Attribute;
class AnimalChest;
class HorseEntitySelector : public EntitySelector {
public:
bool matches(std::shared_ptr<Entity> entity) const;
};
class EntityHorse : public Animal,
public net_minecraft_world::ContainerListener {
public:
eINSTANCEOF GetType() { return eTYPE_HORSE; }
static Entity* create(Level* level) { return new EntityHorse(level); }
private:
static const std::wstring TEX_FOLDER;
static const EntitySelector* PARENT_HORSE_SELECTOR;
static Attribute* JUMP_STRENGTH;
static const int DATA_ID_HORSE_FLAGS = 16;
static const int DATA_ID_TYPE = 19;
static const int DATA_ID_TYPE_VARIANT = 20;
static const int DATA_ID_OWNER_NAME = 21;
static const int DATA_ID_ARMOR = 22;
static const int FLAG_TAME = 1 << 1;
static const int FLAG_SADDLE = 1 << 2;
static const int FLAG_CHESTED = 1 << 3;
static const int FLAG_BRED = 1 << 4;
static const int FLAG_EATING = 1 << 5;
static const int FLAG_STANDING = 1 << 6;
static const int FLAG_OPEN_MOUTH = 1 << 7;
public:
static const int INV_SLOT_SADDLE = 0;
static const int INV_SLOT_ARMOR = 1;
static const int INV_BASE_COUNT = 2;
static const int INV_DONKEY_CHEST_COUNT = 15;
// TODO: USE ENUMS! // Original comment
static const int ARMOR_NONE = 0;
static const int ARMOR_IRON = 1;
static const int ARMOR_GOLD = 2;
static const int ARMOR_DIAMOND = 3;
private:
static const int ARMORS = 4;
static std::wstring ARMOR_TEXTURES[ARMORS];
static int ARMOR_TEXTURES_ID[ARMORS];
static std::wstring ARMOR_HASHES[ARMORS];
static int ARMOR_PROTECTION[ARMORS];
public:
static const int TYPE_HORSE = 0;
static const int TYPE_DONKEY = 1;
static const int TYPE_MULE = 2;
static const int TYPE_UNDEAD = 3;
static const int TYPE_SKELETON = 4;
static const int VARIANT_WHITE = 0;
static const int VARIANT_CREAMY = 1;
static const int VARIANT_CHESTNUT = 2;
static const int VARIANT_BROWN = 3;
static const int VARIANT_BLACK = 4;
static const int VARIANT_GRAY = 5;
static const int VARIANT_DARKBROWN = 6;
private:
static const int VARIANTS = 7;
static std::wstring VARIANT_TEXTURES[VARIANTS];
static int VARIANT_TEXTURES_ID[VARIANTS];
static std::wstring VARIANT_HASHES[VARIANTS];
public:
static const int MARKING_NONE = 0;
static const int MARKING_WHITE_DETAILS = 1;
static const int MARKING_WHITE_FIELDS = 2;
static const int MARKING_WHITE_DOTS = 3;
static const int MARKING_BLACK_DOTS = 4;
private:
static const int MARKINGS = 5;
static std::wstring MARKING_TEXTURES[MARKINGS];
static int MARKING_TEXTURES_ID[MARKINGS];
static std::wstring MARKING_HASHES[MARKINGS];
private:
int countEating; // eating timer
int mouthCounter;
int standCounter;
public:
int tailCounter;
int sprintCounter;
protected:
bool isEntityJumping;
private:
std::shared_ptr<AnimalChest> inventory;
bool hasReproduced;
protected:
int temper;
float playerJumpPendingScale;
private:
bool allowStandSliding;
// animation data
float eatAnim, eatAnimO;
float standAnim, standAnimO;
float mouthAnim, mouthAnimO;
public:
EntityHorse(Level* world);
~EntityHorse();
protected:
virtual void defineSynchedData();
public:
virtual void setType(int i);
virtual int getType();
virtual void setVariant(int i);
virtual int getVariant();
virtual std::wstring getAName();
private:
virtual bool getHorseFlag(int flag);
virtual void setHorseFlag(int flag, bool value);
public:
virtual bool isAdult();
virtual bool isTamed();
virtual bool isRidable();
virtual std::wstring getOwnerName();
virtual void setOwner(const std::wstring& par1Str);
virtual float getFoalScale();
virtual void updateSize(bool isBaby);
virtual bool getIsJumping();
virtual void setTamed(bool flag);
virtual void setIsJumping(bool flag);
virtual bool canBeLeashed();
protected:
virtual void onLeashDistance(float distanceToLeashHolder);
public:
virtual bool isChestedHorse();
virtual int getArmorType();
virtual int getArmorTypeForItem(std::shared_ptr<ItemInstance> armorItem);
virtual bool isEating();
virtual bool isStanding();
virtual bool isBred();
virtual bool getHasReproduced();
virtual void setArmorType(int i);
virtual void setBred(bool flag);
virtual void setChestedHorse(bool flag);
virtual void setReproduced(bool flag);
virtual void setSaddled(bool flag);
virtual int getTemper();
virtual void setTemper(int temper);
virtual int modifyTemper(int amount);
virtual bool hurt(DamageSource* damagesource, float dmg);
virtual int getArmorValue();
virtual bool isPushable();
virtual bool checkSpawningBiome();
virtual void dropBags();
private:
virtual void eatingHorse();
protected:
virtual void causeFallDamage(float fallDistance);
private:
virtual int getInventorySize();
virtual void createInventory();
virtual void updateEquipment();
public:
virtual void containerChanged();
virtual bool canSpawn();
protected:
virtual std::shared_ptr<EntityHorse> getClosestMommy(
std::shared_ptr<Entity> baby, double searchRadius);
public:
virtual double getCustomJump();
protected:
virtual int getDeathSound();
virtual int getDeathLoot();
virtual int getHurtSound();
public:
virtual bool isSaddled();
protected:
virtual int getAmbientSound();
virtual int getMadSound();
private:
int gallopSoundCounter;
protected:
virtual void playStepSound(int xt, int yt, int zt, int t);
virtual void registerAttributes();
public:
virtual int getMaxSpawnClusterSize();
virtual int getMaxTemper();
protected:
virtual float getSoundVolume();
public:
virtual int getAmbientSoundInterval();
virtual bool hasLayeredTextures();
private:
std::wstring layerTextureHashName;
intArray layerTextureLayers;
private:
virtual void clearLayeredTextureInfo();
virtual void rebuildLayeredTextureInfo();
public:
virtual std::wstring getLayeredTextureHashName();
virtual intArray getLayeredTextureLayers();
virtual void openInventory(std::shared_ptr<Player> player);
virtual bool mobInteract(std::shared_ptr<Player> player);
private:
virtual void doPlayerRide(std::shared_ptr<Player> player);
public:
virtual bool isAmuletHorse();
virtual bool canWearArmor();
virtual bool canWearBags();
protected:
virtual bool isImmobile();
public:
virtual bool isPureBreed();
virtual bool isUndead();
virtual bool isSterile();
virtual bool isFood(std::shared_ptr<ItemInstance> itemInstance);
private:
virtual void moveTail();
public:
virtual int nameYOffset();
virtual void die(DamageSource* damagesource);
virtual void aiStep();
virtual void tick();
private:
virtual void openMouth();
public:
// 4J-JEV: Made public for tooltip code, doesn't change state anyway.
virtual bool isReadyForParenting();
public:
virtual bool renderName();
virtual bool rideableEntity();
virtual void setUsingItemFlag(bool flag);
virtual void setEating(bool state);
virtual void setStanding(bool state);
private:
virtual void stand();
public:
virtual void makeMad();
virtual void dropMyStuff();
private:
virtual void dropInventory(std::shared_ptr<Entity> entity,
std::shared_ptr<AnimalChest> animalchest);
public:
virtual bool tameWithName(std::shared_ptr<Player> player);
virtual void travel(float xa, float ya);
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual bool canMate(std::shared_ptr<Animal> partner);
virtual std::shared_ptr<AgableMob> getBreedOffspring(
std::shared_ptr<AgableMob> partner);
virtual MobGroupData* finalizeMobSpawn(
MobGroupData* groupData,
int extraData = 0); // 4J Added extraData param
virtual float getEatAnim(float a);
virtual float getStandAnim(float a);
virtual float getMouthAnim(float a);
protected:
virtual bool useNewAi();
public:
virtual void onPlayerJump(int jumpAmount);
protected:
virtual void spawnTamingParticles(bool success);
public:
virtual void handleEntityEvent(uint8_t id);
virtual void positionRider();
private:
virtual float generateRandomMaxHealth();
virtual double generateRandomJumpStrength();
virtual double generateRandomSpeed();
std::shared_ptr<Player> getOwner();
public:
class HorseGroupData : public MobGroupData {
public:
int horseType;
int horseVariant;
HorseGroupData(int type, int variant);
};
static bool isHorseArmor(int itemId);
virtual bool onLadder();
};

View file

@ -81,8 +81,8 @@ void ExperienceOrb::tick() {
yd = 0.2f;
xd = (random->nextFloat() - random->nextFloat()) * 0.2f;
zd = (random->nextFloat() - random->nextFloat()) * 0.2f;
level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.4f,
2.0f + random->nextFloat() * 0.4f);
playSound(eSoundType_RANDOM_FIZZ, 0.4f,
2.0f + random->nextFloat() * 0.4f);
}
checkInTile(x, (bb->y0 + bb->y1) / 2, z);
@ -150,7 +150,8 @@ bool ExperienceOrb::updateInWaterState() {
void ExperienceOrb::burn(int dmg) { hurt(DamageSource::inFire, dmg); }
bool ExperienceOrb::hurt(DamageSource* source, int damage) {
bool ExperienceOrb::hurt(DamageSource* source, float damage) {
if (isInvulnerable()) return false;
markHurt();
health -= damage;
if (health <= 0) {
@ -177,8 +178,8 @@ void ExperienceOrb::playerTouch(std::shared_ptr<Player> player) {
if (throwTime == 0 && player->takeXpDelay == 0) {
player->takeXpDelay = 2;
// 4J - sound change brought forward from 1.2.3
level->playSound(
shared_from_this(), eSoundType_RANDOM_ORB, 0.1f,
playSound(
eSoundType_RANDOM_ORB, 0.1f,
0.5f * ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.8f));
player->take(shared_from_this(), 1);
player->increaseXp(value);

View file

@ -45,7 +45,7 @@ protected:
virtual void burn(int dmg);
public:
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
virtual void addAdditonalSaveData(CompoundTag* entityTag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual void playerTouch(std::shared_ptr<Player> player);

View file

@ -40,8 +40,8 @@ EyeOfEnderSignal::EyeOfEnderSignal(Level* level, double x, double y, double z)
setSize(0.25f, 0.25f);
this->setPos(x, y, z);
this->heightOffset = 0;
setPos(x, y, z);
heightOffset = 0;
}
void EyeOfEnderSignal::signalTo(double tx, int ty, double tz) {
@ -68,8 +68,8 @@ void EyeOfEnderSignal::lerpMotion(double xd, double yd, double zd) {
this->zd = zd;
if (xRotO == 0 && yRotO == 0) {
float sd = (float)sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = this->xRot = (float)(atan2(yd, (double)sd) * 180 / PI);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, (double)sd) * 180 / PI);
}
}

View file

@ -55,8 +55,8 @@ Fireball::Fireball(Level* level, double x, double y, double z, double xa,
setSize(16 / 16.0f, 16 / 16.0f);
this->moveTo(x, y, z, yRot, xRot);
this->setPos(x, y, z);
moveTo(x, y, z, yRot, xRot);
setPos(x, y, z);
double dd = sqrt(xa * xa + ya * ya + za * za);
@ -74,8 +74,8 @@ Fireball::Fireball(Level* level, double x, double y, double z, double xa,
}
}
Fireball::Fireball(Level* level, std::shared_ptr<Mob> mob, double xa, double ya,
double za)
Fireball::Fireball(Level* level, std::shared_ptr<LivingEntity> mob, double xa,
double ya, double za)
: Entity(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
@ -83,13 +83,13 @@ Fireball::Fireball(Level* level, std::shared_ptr<Mob> mob, double xa, double ya,
_init();
this->owner = mob;
owner = mob;
setSize(16 / 16.0f, 16 / 16.0f);
this->moveTo(mob->x, mob->y, mob->z, mob->yRot, mob->xRot);
this->setPos(x, y, z);
this->heightOffset = 0;
moveTo(mob->x, mob->y, mob->z, mob->yRot, mob->xRot);
setPos(x, y, z);
heightOffset = 0;
xd = yd = zd = 0.0;
@ -177,7 +177,7 @@ void Fireball::tick() {
}
std::shared_ptr<Entity> hitEntity = nullptr;
std::vector<std::shared_ptr<Entity> >* objects = level->getEntities(
shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1));
shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1));
double nearest = 0;
AUTO_VAR(itEnd, objects->end());
for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) {
@ -214,8 +214,8 @@ void Fireball::tick() {
z += zd;
double sd = sqrt(xd * xd + zd * zd);
yRot = (float)(atan2(xd, zd) * 180 / PI);
xRot = (float)(atan2(yd, sd) * 180 / PI);
yRot = (float)(atan2(zd, xd) * 180 / PI) + 90;
xRot = (float)(atan2(sd, yd) * 180 / PI) - 90;
while (xRot - xRotO < -180) xRotO -= 360;
while (xRot - xRotO >= 180) xRotO += 360;
@ -226,7 +226,7 @@ void Fireball::tick() {
xRot = xRotO + (xRot - xRotO) * 0.2f;
yRot = yRotO + (yRot - yRotO) * 0.2f;
float inertia = 0.95f;
float inertia = getInertia();
if (isInWater()) {
for (int i = 0; i < 4; i++) {
float s = 1 / 4.0f;
@ -260,24 +260,7 @@ void Fireball::tick() {
setPos(x, y, z);
}
void Fireball::onHit(HitResult* res) {
if (!level->isClientSide) {
if (res->entity != NULL) {
DamageSource* damageSource = DamageSource::fireball(
std::dynamic_pointer_cast<Fireball>(shared_from_this()), owner);
if (res->entity->hurt(damageSource, 6)) {
} else {
}
delete damageSource;
}
bool destroyBlocks =
true; // level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
level->explode(nullptr, x, y, z, 1, true, destroyBlocks);
remove();
}
}
float Fireball::getInertia() { return 0.95f; }
void Fireball::addAdditonalSaveData(CompoundTag* tag) {
tag->putShort(L"xTile", (short)xTile);
@ -285,8 +268,7 @@ void Fireball::addAdditonalSaveData(CompoundTag* tag) {
tag->putShort(L"zTile", (short)zTile);
tag->putByte(L"inTile", (uint8_t)lastTile);
tag->putByte(L"inGround", (uint8_t)(inGround ? 1 : 0));
tag->put(L"direction",
this->newDoubleList(3, this->xd, this->yd, this->zd));
tag->put(L"direction", newDoubleList(3, xd, yd, zd));
}
void Fireball::readAdditionalSaveData(CompoundTag* tag) {
@ -301,11 +283,11 @@ void Fireball::readAdditionalSaveData(CompoundTag* tag) {
if (tag->contains(L"direction")) {
ListTag<DoubleTag>* listTag =
(ListTag<DoubleTag>*)tag->getList(L"direction");
this->xd = ((DoubleTag*)listTag->get(0))->data;
this->yd = ((DoubleTag*)listTag->get(1))->data;
this->zd = ((DoubleTag*)listTag->get(2))->data;
xd = ((DoubleTag*)listTag->get(0))->data;
yd = ((DoubleTag*)listTag->get(1))->data;
zd = ((DoubleTag*)listTag->get(2))->data;
} else {
this->remove();
remove();
}
}
@ -313,7 +295,8 @@ bool Fireball::isPickable() { return true; }
float Fireball::getPickRadius() { return 1; }
bool Fireball::hurt(DamageSource* source, int damage) {
bool Fireball::hurt(DamageSource* source, float damage) {
if (isInvulnerable()) return false;
markHurt();
if (source->getEntity() != NULL) {
@ -326,10 +309,9 @@ bool Fireball::hurt(DamageSource* source, int damage) {
yPower = yd * 0.1;
zPower = zd * 0.1;
}
std::shared_ptr<Mob> mob =
std::dynamic_pointer_cast<Mob>(source->getEntity());
if (mob != NULL) {
owner = mob;
if (source->getEntity()->instanceof(eTYPE_LIVINGENTITY)) {
owner =
std::dynamic_pointer_cast<LivingEntity>(source->getEntity());
}
return true;
}
@ -342,8 +324,6 @@ float Fireball::getBrightness(float a) { return 1.0f; }
int Fireball::getLightColor(float a) { return 15 << 20 | 15 << 4; }
bool Fireball::shouldBurn() { return true; }
int Fireball::getIcon() { return 14 + 2 * 16; }
ePARTICLE_TYPE Fireball::getTrailParticleType() { return eParticleType_smoke; }
bool Fireball::shouldBurn() { return true; }

View file

@ -8,7 +8,6 @@ class HitResult;
class Fireball : public Entity {
public:
eINSTANCEOF GetType() { return eTYPE_FIREBALL; }
static Entity* create(Level* level) { return new Fireball(level); }
private:
int xTile;
@ -20,7 +19,7 @@ private:
bool inGround;
public:
std::shared_ptr<Mob> owner;
std::shared_ptr<LivingEntity> owner;
private:
int life;
@ -42,30 +41,29 @@ public:
Fireball(Level* level, double x, double y, double z, double xa, double ya,
double za);
Fireball(Level* level, std::shared_ptr<Mob> mob, double xa, double ya,
double za);
Fireball(Level* level, std::shared_ptr<LivingEntity> mob, double xa,
double ya, double za);
public:
virtual void tick();
protected:
virtual void onHit(HitResult* res);
virtual float getInertia();
virtual void onHit(HitResult* res) = 0;
public:
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
virtual bool isPickable();
virtual float getPickRadius();
virtual bool hurt(DamageSource* source, int damage);
virtual bool hurt(DamageSource* source, float damage);
virtual float getShadowHeightOffs();
virtual float getBrightness(float a);
virtual int getLightColor(float a);
// 4J Added TU9
virtual bool shouldBurn();
virtual int getIcon();
protected:
// 4J Added TU9
virtual ePARTICLE_TYPE getTrailParticleType();
virtual bool shouldBurn();
};

View file

@ -63,19 +63,19 @@ FishingHook::FishingHook(Level* level, std::shared_ptr<Player> mob)
: Entity(level) {
_init();
this->owner = mob;
owner = mob;
// 4J Stu - Moved this outside the ctor
// owner->fishing = std::dynamic_pointer_cast<FishingHook>(
// shared_from_this() );
this->moveTo(mob->x, mob->y + 1.62 - mob->heightOffset, mob->z, mob->yRot,
mob->xRot);
moveTo(mob->x, mob->y + 1.62 - mob->heightOffset, mob->z, mob->yRot,
mob->xRot);
x -= Mth::cos(yRot / 180 * PI) * 0.16f;
y -= 0.1f;
z -= Mth::sin(yRot / 180 * PI) * 0.16f;
this->setPos(x, y, z);
this->heightOffset = 0;
setPos(x, y, z);
heightOffset = 0;
float speed = 0.4f;
xd = (-Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI)) * speed;
@ -115,8 +115,8 @@ void FishingHook::shoot(double xd, double yd, double zd, float pow,
double sd = sqrt(xd * xd + zd * zd);
yRotO = this->yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = this->xRot = (float)(atan2(yd, sd) * 180 / PI);
yRotO = yRot = (float)(atan2(xd, zd) * 180 / PI);
xRotO = xRot = (float)(atan2(yd, sd) * 180 / PI);
life = 0;
}
@ -130,9 +130,9 @@ void FishingHook::lerpTo(double x, double y, double z, float yRot, float xRot,
lSteps = steps;
this->xd = lxd;
this->yd = lyd;
this->zd = lzd;
xd = lxd;
yd = lyd;
zd = lzd;
}
void FishingHook::lerpMotion(double xd, double yd, double zd) {
@ -155,8 +155,8 @@ void FishingHook::tick() {
xRot += (float)((lxr - xRot) / lSteps);
lSteps--;
this->setPos(xt, yt, zt);
this->setRot(yRot, xRot);
setPos(xt, yt, zt);
setRot(yRot, xRot);
return;
}
@ -164,7 +164,7 @@ void FishingHook::tick() {
std::shared_ptr<ItemInstance> selectedItem = owner->getSelectedItem();
if (owner->removed || !owner->isAlive() || selectedItem == NULL ||
selectedItem->getItem() != Item::fishingRod ||
this->distanceToSqr(owner) > 32 * 32) {
distanceToSqr(owner) > 32 * 32) {
remove();
owner->fishing = nullptr;
return;
@ -214,7 +214,7 @@ void FishingHook::tick() {
}
std::shared_ptr<Entity> hitEntity = nullptr;
std::vector<std::shared_ptr<Entity> >* objects = level->getEntities(
shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1));
shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1));
double nearest = 0;
AUTO_VAR(itEnd, objects->end());
for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) {
@ -243,8 +243,8 @@ void FishingHook::tick() {
if (res->entity != NULL) {
// 4J Stu Move fix for : fix for #48587 - CRASH: Code: Gameplay:
// Hitting another player with the fishing bobber crashes the game.
// [Fishing pole, line] Incorrect std::dynamic_pointer_cast used
// around the shared_from_this()
// [Fishing pole, line] Incorrect dynamic_pointer_cast used around
// the shared_from_this()
DamageSource* damageSource =
DamageSource::thrown(shared_from_this(), owner);
if (res->entity->hurt(damageSource, 0)) {
@ -305,8 +305,8 @@ void FishingHook::tick() {
if (random->nextInt(nibbleOdds) == 0) {
nibble = random->nextInt(30) + 10;
yd -= 0.2f;
level->playSound(
shared_from_this(), eSoundType_RANDOM_SPLASH, 0.25f,
playSound(
eSoundType_RANDOM_SPLASH, 0.25f,
1 + (random->nextFloat() - random->nextFloat()) * 0.4f);
float yt = (float)Mth::floor(bb->y0);
for (int i = 0; i < 1 + bbWidth * 20; i++) {
@ -398,7 +398,7 @@ int FishingHook::retrieve() {
owner->level->addEntity(
std::shared_ptr<ExperienceOrb>(new ExperienceOrb(
owner->level, owner->x, owner->y + 0.5f, owner->z + 0.5f,
random->nextInt(3) + 1))); // 4J Stu brought forward from 1.4
random->nextInt(6) + 1))); // 4J Stu brought forward from 1.4
dmg = 1;
}
if (inGround) dmg = 2;

View file

@ -3,8 +3,10 @@
#include "../../Headers/net.minecraft.world.phys.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.entity.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.projectile.h"
#include "../../Headers/net.minecraft.world.entity.player.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "../../Headers/net.minecraft.world.item.h"
#include "../../Headers/net.minecraft.world.damagesource.h"
#include "../../Headers/net.minecraft.stats.h"
@ -14,6 +16,7 @@
#include "../../Util/SoundTypes.h"
void Ghast::_init() {
explosionPower = 1;
floatDuration = 0;
target = nullptr;
retargetTime = 0;
@ -29,28 +32,27 @@ Ghast::Ghast(Level* level) : FlyingMob(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
registerAttributes();
setHealth(getMaxHealth());
_init();
this->textureIdx = TN_MOB_GHAST; // 4J was L"/mob/ghast.png";
this->setSize(4, 4);
this->fireImmune = true;
setSize(4, 4);
fireImmune = true;
xpReward = Enemy::XP_REWARD_MEDIUM;
}
bool Ghast::hurt(DamageSource* source, int dmg) {
bool Ghast::isCharging() { return entityData->getByte(DATA_IS_CHARGING) != 0; }
bool Ghast::hurt(DamageSource* source, float dmg) {
if (isInvulnerable()) return false;
if (source->getMsgId() == ChatPacket::e_ChatDeathFireball) {
std::shared_ptr<Player> player =
std::dynamic_pointer_cast<Player>(source->getEntity());
if (player != NULL) {
if ((source->getEntity() != NULL) &&
source->getEntity()->instanceof(eTYPE_PLAYER)) {
// reflected fireball, kill the ghast
FlyingMob::hurt(source, 1000);
player->awardStat(GenericStats::ghast(),
GenericStats::param_ghast());
std::dynamic_pointer_cast<Player>(source->getEntity())
->awardStat(GenericStats::ghast(), GenericStats::param_ghast());
return true;
}
}
@ -64,14 +66,10 @@ void Ghast::defineSynchedData() {
entityData->define(DATA_IS_CHARGING, (uint8_t)0);
}
int Ghast::getMaxHealth() { return 10; }
void Ghast::registerAttributes() {
FlyingMob::registerAttributes();
void Ghast::tick() {
FlyingMob::tick();
uint8_t current = entityData->getByte(DATA_IS_CHARGING);
// this->textureName = current == 1 ? L"/mob/ghast_fire.png" :
// L"/mob/ghast.png"; // 4J replaced with following line
this->textureIdx = current == 1 ? TN_MOB_GHAST_FIRE : TN_MOB_GHAST;
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10);
}
void Ghast::serverAiStep() {
@ -125,7 +123,7 @@ void Ghast::serverAiStep() {
double zdd = target->z - z;
yBodyRot = yRot = -(float)atan2(xdd, zdd) * 180 / PI;
if (this->canSee(target)) {
if (canSee(target)) {
if (charge == 10) {
// 4J - change brought forward from 1.2.3
level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_WARNING,
@ -136,11 +134,12 @@ void Ghast::serverAiStep() {
// 4J - change brought forward from 1.2.3
level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_FIREBALL,
(int)x, (int)y, (int)z, 0);
std::shared_ptr<Fireball> ie =
std::shared_ptr<Fireball>(new Fireball(
std::shared_ptr<LargeFireball> ie =
std::shared_ptr<LargeFireball>(new LargeFireball(
level,
std::dynamic_pointer_cast<Mob>(shared_from_this()), xdd,
ydd, zdd));
ie->explosionPower = explosionPower;
double d = 4;
Vec3* v = getViewVector(1);
ie->x = x + v->x * d;
@ -186,7 +185,7 @@ int Ghast::getHurtSound() { return eSoundType_MOB_GHAST_SCREAM; }
int Ghast::getDeathSound() { return eSoundType_MOB_GHAST_DEATH; }
int Ghast::getDeathLoot() { return Item::sulphur->id; }
int Ghast::getDeathLoot() { return Item::gunpowder_Id; }
void Ghast::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) {
int count = random->nextInt(2) + random->nextInt(1 + playerBonusLevel);
@ -195,7 +194,7 @@ void Ghast::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) {
}
count = random->nextInt(3) + random->nextInt(1 + playerBonusLevel);
for (int i = 0; i < count; i++) {
spawnAtLocation(Item::sulphur_Id, 1);
spawnAtLocation(Item::gunpowder_Id, 1);
}
}
@ -209,3 +208,13 @@ bool Ghast::canSpawn() {
}
int Ghast::getMaxSpawnClusterSize() { return 1; }
void Ghast::addAdditonalSaveData(CompoundTag* tag) {
FlyingMob::addAdditonalSaveData(tag);
tag->putInt(L"ExplosionPower", explosionPower);
}
void Ghast::readAdditionalSaveData(CompoundTag* tag) {
FlyingMob::readAdditionalSaveData(tag);
if (tag->contains(L"ExplosionPower"))
explosionPower = tag->getInt(L"ExplosionPower");
}

View file

@ -27,21 +27,19 @@ public:
int charge;
private:
int explosionPower;
void _init();
public:
Ghast(Level* level);
virtual bool hurt(DamageSource* source, int dmg);
virtual bool isCharging();
virtual bool hurt(DamageSource* source, float dmg);
protected:
virtual void defineSynchedData();
public:
int getMaxHealth();
public:
virtual void tick();
virtual void registerAttributes();
protected:
virtual void serverAiStep();
@ -60,4 +58,6 @@ protected:
public:
virtual bool canSpawn();
virtual int getMaxSpawnClusterSize();
virtual void addAdditonalSaveData(CompoundTag* tag);
virtual void readAdditionalSaveData(CompoundTag* tag);
};

View file

@ -1,5 +1,7 @@
#include "../../Platform/stdafx.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.entity.ai.attributes.h"
#include "../../Headers/net.minecraft.world.entity.monster.h"
#include "Giant.h"
#include "../../../Minecraft.Client/Textures/Textures.h"
@ -7,19 +9,19 @@ Giant::Giant(Level* level) : Monster(level) {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
registerAttributes();
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
health = getMaxHealth();
this->textureIdx = TN_MOB_ZOMBIE; // 4J was L"/mob/zombie.png";
runSpeed = 0.5f;
attackDamage = 50;
this->heightOffset *= 6;
this->setSize(bbWidth * 6, bbHeight * 6);
heightOffset *= 6;
setSize(bbWidth * 6, bbHeight * 6);
}
int Giant::getMaxHealth() { return 100; }
void Giant::registerAttributes() {
Monster::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(100);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.5f);
getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(50);
}
float Giant::getWalkTargetValue(int x, int y, int z) {
return level->getBrightness(x, y, z) - 0.5f;

View file

@ -11,6 +11,9 @@ public:
Giant(Level* level);
int getMaxHealth();
protected:
virtual void registerAttributes();
public:
virtual float getWalkTargetValue(int x, int y, int z);
};

View file

@ -16,6 +16,8 @@ void ItemFrame::_init() {
// 4J Stu - This function call had to be moved here from the Entity ctor to
// ensure that the derived version of the function is called
this->defineSynchedData();
dropChance = 1;
}
ItemFrame::ItemFrame(Level* level) : HangingEntity(level) { _init(); }
@ -31,19 +33,40 @@ void ItemFrame::defineSynchedData() {
getEntityData()->define(DATA_ROTATION, (uint8_t)0);
}
void ItemFrame::dropItem() {
spawnAtLocation(
std::shared_ptr<ItemInstance>(new ItemInstance(Item::frame)), 0.0f);
std::shared_ptr<ItemInstance> item = getItem();
if (item != NULL) {
std::shared_ptr<MapItemSavedData> data =
Item::map->getSavedData(item, level);
data->removeItemFrameDecoration(item);
bool ItemFrame::shouldRenderAtSqrDistance(double distance) {
double size = 16;
size *= 64.0f * viewScale;
return distance < size * size;
}
std::shared_ptr<ItemInstance> itemToDrop = item->copy();
itemToDrop->setFramed(nullptr);
spawnAtLocation(itemToDrop, 0.0f);
void ItemFrame::dropItem(std::shared_ptr<Entity> causedBy) {
std::shared_ptr<ItemInstance> item = getItem();
if (causedBy != NULL && causedBy->instanceof(eTYPE_PLAYER)) {
if (std::dynamic_pointer_cast<Player>(causedBy)->abilities.instabuild) {
removeFramedMap(item);
return;
}
}
spawnAtLocation(
std::shared_ptr<ItemInstance>(new ItemInstance(Item::frame)), 0);
if ((item != NULL) && (random->nextFloat() < dropChance)) {
item = item->copy();
removeFramedMap(item);
spawnAtLocation(item, 0);
}
}
void ItemFrame::removeFramedMap(std::shared_ptr<ItemInstance> item) {
if (item == NULL) return;
if (item->id == Item::map_Id) {
std::shared_ptr<MapItemSavedData> mapItemSavedData =
Item::map->getSavedData(item, level);
mapItemSavedData->removeItemFrameDecoration(item);
// mapItemSavedData.decorations.remove("frame-" + entityId);
}
item->setFramed(nullptr);
}
std::shared_ptr<ItemInstance> ItemFrame::getItem() {
@ -72,7 +95,7 @@ void ItemFrame::addAdditonalSaveData(CompoundTag* tag) {
if (getItem() != NULL) {
tag->putCompound(L"Item", getItem()->save(new CompoundTag()));
tag->putByte(L"ItemRotation", (uint8_t)getRotation());
// tag->putFloat(L"ItemDropChance", dropChance);
tag->putFloat(L"ItemDropChance", dropChance);
}
HangingEntity::addAdditonalSaveData(tag);
}
@ -83,8 +106,8 @@ void ItemFrame::readAdditionalSaveData(CompoundTag* tag) {
setItem(ItemInstance::fromTag(itemTag));
setRotation(tag->getByte(L"ItemRotation"));
// if (tag->contains(L"ItemDropChance")) dropChance =
// tag->getFloat(L"ItemDropChance");
if (tag->contains(L"ItemDropChance"))
dropChance = tag->getFloat(L"ItemDropChance");
}
HangingEntity::readAdditionalSaveData(tag);
}

View file

@ -14,6 +14,8 @@ private:
static const int DATA_ITEM = 2;
static const int DATA_ROTATION = 3;
float dropChance;
private:
void _init();
@ -23,9 +25,15 @@ public:
protected:
virtual void defineSynchedData();
public:
virtual int getWidth() { return 9; }
virtual int getHeight() { return 9; }
virtual void dropItem();
virtual bool shouldRenderAtSqrDistance(double distance);
virtual void dropItem(std::shared_ptr<Entity> causedBy);
private:
void removeFramedMap(std::shared_ptr<ItemInstance> item);
public:
std::shared_ptr<ItemInstance> getItem();

Some files were not shown because too many files have changed in this diff Show more