Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
25 kB · 1077 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077#include "stdafx.h"#include "JavaMath.h"#include "net.minecraft.network.packet.h"#include "net.minecraft.world.level.tile.h"#include "net.minecraft.world.phys.h"#include "net.minecraft.world.entity.h"#include "net.minecraft.world.entity.ai.attributes.h"#include "net.minecraft.world.entity.ai.control.h"#include "net.minecraft.world.entity.ai.navigation.h"#include "net.minecraft.world.entity.ai.sensing.h"#include "net.minecraft.world.entity.player.h"#include "net.minecraft.world.entity.animal.h"#include "net.minecraft.world.entity.monster.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.level.h"#include "net.minecraft.world.level.material.h"#include "net.minecraft.world.damagesource.h"#include "net.minecraft.world.effect.h"#include "net.minecraft.world.item.alchemy.h"#include "net.minecraft.world.item.enchantment.h"#include "net.minecraft.world.h"#include "..\Minecraft.Client\ServerLevel.h"#include "..\Minecraft.Client\EntityTracker.h"#include "com.mojang.nbt.h"#include "Mob.h"#include "..\Minecraft.Client\Textures.h"#include "SoundTypes.h"#include "BasicTypeContainers.h"#include "ParticleTypes.h"#include "GenericStats.h"#include "ItemEntity.h"
const float Mob::MAX_WEARING_ARMOR_CHANCE = 0.15f;const float Mob::MAX_PICKUP_LOOT_CHANCE = 0.55f;const float Mob::MAX_ENCHANTED_ARMOR_CHANCE = 0.50f;const float Mob::MAX_ENCHANTED_WEAPON_CHANCE = 0.25f;
void Mob::_init(){ ambientSoundTime = 0; xpReward = 0; defaultLookAngle = 0.0f; lookingAt = nullptr; lookTime = 0; target = nullptr; sensing = NULL;
equipment = ItemInstanceArray(5); dropChances = floatArray(5); for(unsigned int i = 0; i < 5; ++i) { equipment[i] = nullptr; dropChances[i] = 0.0f; }
_canPickUpLoot = false; persistenceRequired = false;
_isLeashed = false; leashHolder = nullptr; leashInfoTag = NULL;}
Mob::Mob( Level* level) : LivingEntity(level){ MemSect(57); _init(); MemSect(0);
MemSect(58); // 4J Stu - We call this again in the derived classes, but need to do it here for some internal members registerAttributes(); MemSect(0);
lookControl = new LookControl(this); moveControl = new MoveControl(this); jumpControl = new JumpControl(this); bodyControl = new BodyControl(this); navigation = new PathNavigation(this, level); sensing = new Sensing(this);
for (int i = 0; i < 5; i++) { dropChances[i] = 0.085f; }}
Mob::~Mob(){ if(lookControl != NULL) delete lookControl; if(moveControl != NULL) delete moveControl; if(jumpControl != NULL) delete jumpControl; if(bodyControl != NULL) delete bodyControl; if(navigation != NULL) delete navigation; if(sensing != NULL) delete sensing;
if(leashInfoTag != NULL) delete leashInfoTag;
if(equipment.data != NULL) delete [] equipment.data; delete [] dropChances.data;}
void Mob::registerAttributes(){ LivingEntity::registerAttributes();
getAttributes()->registerAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(16);}
LookControl *Mob::getLookControl(){ return lookControl;}
MoveControl *Mob::getMoveControl(){ return moveControl;}
JumpControl *Mob::getJumpControl(){ return jumpControl;}
PathNavigation *Mob::getNavigation(){ return navigation;}
Sensing *Mob::getSensing(){ return sensing;}
shared_ptr<LivingEntity> Mob::getTarget(){ return target;}
void Mob::setTarget(shared_ptr<LivingEntity> target){ this->target = target;}
bool Mob::canAttackType(eINSTANCEOF targetType){ return !(targetType == eTYPE_CREEPER || targetType == eTYPE_GHAST);}
// Called by eatTileGoalvoid Mob::ate(){}
void Mob::defineSynchedData() { LivingEntity::defineSynchedData(); entityData->define(DATA_CUSTOM_NAME_VISIBLE, (byte) 0); entityData->define(DATA_CUSTOM_NAME, L"");}
int Mob::getAmbientSoundInterval() { return 20 * 4;}
void Mob::playAmbientSound() { MemSect(31); int ambient = getAmbientSound(); if (ambient != -1) { playSound(ambient, getSoundVolume(), getVoicePitch()); } MemSect(0);}
void Mob::baseTick() { LivingEntity::baseTick();
if (isAlive() && random->nextInt(1000) < ambientSoundTime++) { ambientSoundTime = -getAmbientSoundInterval();
playAmbientSound(); }}
int Mob::getExperienceReward(shared_ptr<Player> killedBy){ if (xpReward > 0) { int result = xpReward;
ItemInstanceArray slots = getEquipmentSlots(); for (int i = 0; i < slots.length; i++) { if (slots[i] != NULL && dropChances[i] <= 1) { result += 1 + random->nextInt(3); } }
return result; } else { return xpReward; }}void Mob::spawnAnim() { for (int i = 0; i < 20; i++) { double xa = random->nextGaussian() * 0.02; double ya = random->nextGaussian() * 0.02; double za = random->nextGaussian() * 0.02; double dd = 10; level->addParticle(eParticleType_explode, x + random->nextFloat() * bbWidth * 2 - bbWidth - xa * dd, y + random->nextFloat() * bbHeight - ya * dd, z + random->nextFloat() * bbWidth * 2 - bbWidth - za * dd, xa, ya, za); }}
void Mob::tick() { LivingEntity::tick();
if (!level->isClientSide) { tickLeash(); }}
float Mob::tickHeadTurn(float yBodyRotT, float walkSpeed){ if (useNewAi()) { bodyControl->clientTick(); return walkSpeed; } else { return LivingEntity::tickHeadTurn(yBodyRotT, walkSpeed); }}
int Mob::getAmbientSound() { return -1;}
int Mob::getDeathLoot(){ return 0;}
void Mob::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) { int loot = getDeathLoot(); if (loot > 0) { int count = random->nextInt(3); if (playerBonusLevel > 0) { count += random->nextInt(playerBonusLevel + 1); } for (int i = 0; i < count; i++) spawnAtLocation(loot, 1); }}
void Mob::addAdditonalSaveData(CompoundTag *entityTag) { LivingEntity::addAdditonalSaveData(entityTag); entityTag->putBoolean(L"CanPickUpLoot", canPickUpLoot()); entityTag->putBoolean(L"PersistenceRequired", persistenceRequired);
ListTag<CompoundTag> *gear = new ListTag<CompoundTag>(); for (int i = 0; i < equipment.length; i++) { CompoundTag *tag = new CompoundTag(); if (equipment[i] != NULL) equipment[i]->save(tag); gear->add(tag); } entityTag->put(L"Equipment", gear);
ListTag<FloatTag> *dropChanceList = new ListTag<FloatTag>(); for (int i = 0; i < dropChances.length; i++) { dropChanceList->add(new FloatTag( _toString(i), dropChances[i])); } entityTag->put(L"DropChances", dropChanceList); entityTag->putString(L"CustomName", getCustomName()); entityTag->putBoolean(L"CustomNameVisible", isCustomNameVisible());
// leash info entityTag->putBoolean(L"Leashed", _isLeashed); if (leashHolder != NULL) { CompoundTag *leashTag = new CompoundTag(L"Leash"); if ( leashHolder->instanceof(eTYPE_LIVINGENTITY) ) { // a walking, talking, leash holder leashTag->putString(L"UUID", leashHolder->getUUID()); } else if ( leashHolder->instanceof(eTYPE_HANGING_ENTITY) ) { // a fixed holder (that doesn't save itself) shared_ptr<HangingEntity> hangInThere = dynamic_pointer_cast<HangingEntity>(leashHolder); leashTag->putInt(L"X", hangInThere->xTile); leashTag->putInt(L"Y", hangInThere->yTile); leashTag->putInt(L"Z", hangInThere->zTile); } entityTag->put(L"Leash", leashTag); }}
void Mob::readAdditionalSaveData(CompoundTag *tag) { LivingEntity::readAdditionalSaveData(tag);
setCanPickUpLoot(tag->getBoolean(L"CanPickUpLoot")); persistenceRequired = tag->getBoolean(L"PersistenceRequired"); if (tag->contains(L"CustomName") && tag->getString(L"CustomName").length() > 0) setCustomName(tag->getString(L"CustomName")); setCustomNameVisible(tag->getBoolean(L"CustomNameVisible"));
if (tag->contains(L"Equipment")) { ListTag<CompoundTag> *gear = (ListTag<CompoundTag> *) tag->getList(L"Equipment");
for (int i = 0; i < equipment.length; i++) { equipment[i] = ItemInstance::fromTag(gear->get(i)); } }
if (tag->contains(L"DropChances")) { ListTag<FloatTag> *items = (ListTag<FloatTag> *) tag->getList(L"DropChances"); for (int i = 0; i < items->size(); i++) { dropChances[i] = items->get(i)->data; } }
_isLeashed = tag->getBoolean(L"Leashed"); if (_isLeashed && tag->contains(L"Leash")) { leashInfoTag = (CompoundTag *)tag->getCompound(L"Leash")->copy(); }}
void Mob::setYya(float yya){ this->yya = yya;}
void Mob::setSpeed(float speed){ LivingEntity::setSpeed(speed); setYya(speed);}
void Mob::aiStep() { LivingEntity::aiStep();
if (!level->isClientSide && canPickUpLoot() && !dead && level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) { vector<shared_ptr<Entity> > *entities = level->getEntitiesOfClass(typeid(ItemEntity), bb->grow(1, 0, 1)); for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { shared_ptr<ItemEntity> entity = dynamic_pointer_cast<ItemEntity>(*it); if (entity->removed || entity->getItem() == NULL) continue; shared_ptr<ItemInstance> item = entity->getItem(); int slot = getEquipmentSlotForItem(item);
if (slot > -1) { bool replace = true; shared_ptr<ItemInstance> current = getCarried(slot);
if (current != NULL) { if (slot == SLOT_WEAPON) { WeaponItem *newWeapon = dynamic_cast<WeaponItem *>(item->getItem()); WeaponItem *oldWeapon = dynamic_cast<WeaponItem *>(current->getItem()); if ( newWeapon != NULL && oldWeapon == NULL) { replace = true; } else if (newWeapon != NULL && oldWeapon != NULL) { if (newWeapon->getTierDamage() == oldWeapon->getTierDamage()) { replace = item->getAuxValue() > current->getAuxValue() || item->hasTag() && !current->hasTag(); } else { replace = newWeapon->getTierDamage() > oldWeapon->getTierDamage(); } } else { replace = false; } } else { ArmorItem *newArmor = dynamic_cast<ArmorItem *>(item->getItem()); ArmorItem *oldArmor = dynamic_cast<ArmorItem *>(current->getItem()); if (newArmor != NULL && oldArmor == NULL) { replace = true; } else if (newArmor != NULL && oldArmor != NULL) { if (newArmor->defense == oldArmor->defense) { replace = item->getAuxValue() > current->getAuxValue() || item->hasTag() && !current->hasTag(); } else { replace = newArmor->defense > oldArmor->defense; } } else { replace = false; } } }
if (replace) { if (current != NULL && random->nextFloat() - 0.1f < dropChances[slot]) { spawnAtLocation(current, 0); }
setEquippedSlot(slot, item); dropChances[slot] = 2; persistenceRequired = true; take(entity, 1); entity->remove(); } } } delete entities; }}
bool Mob::useNewAi(){ return false;}
bool Mob::removeWhenFarAway() { return true;}
void Mob::checkDespawn() { if (persistenceRequired) { noActionTime = 0; return; } shared_ptr<Entity> player = level->getNearestPlayer(shared_from_this(), -1); if (player != NULL) { double xd = player->x - x; double yd = player->y - y; double zd = player->z - z; double sd = xd * xd + yd * yd + zd * zd;
if (removeWhenFarAway() && sd > 128 * 128) { remove(); }
if (noActionTime > 20 * 30 && random->nextInt(800) == 0 && sd > 32 * 32 && removeWhenFarAway()) { remove(); } else if (sd < 32 * 32) { noActionTime = 0; } }}
void Mob::newServerAiStep(){ PIXBeginNamedEvent(0,"Tick target selector for %d",GetType()); MemSect(51); noActionTime++; PIXBeginNamedEvent(0,"Check despawn"); checkDespawn(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick sensing"); sensing->tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick target selector"); targetSelector.tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick goal selectors"); goalSelector.tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick navigation"); navigation->tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick server ai mob step"); serverAiMobStep(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick move"); moveControl->tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick look"); lookControl->tick(); PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Tick jump"); jumpControl->tick(); PIXEndNamedEvent(); // Consider this for extra strolling if it is protected against despawning. We aren't interested in ones that aren't protected as the whole point of this // extra wandering is to potentially transition from protected to not protected. PIXBeginNamedEvent(0,"Consider extra wandering"); considerForExtraWandering( isDespawnProtected() ); PIXEndNamedEvent(); MemSect(0); PIXEndNamedEvent();}
void Mob::serverAiStep() { LivingEntity::serverAiStep();
xxa = 0; yya = 0;
checkDespawn();
float lookDistance = 8; if (random->nextFloat() < 0.02f) { shared_ptr<Player> player = level->getNearestPlayer(shared_from_this(), lookDistance); if (player != NULL) { lookingAt = player; lookTime = 10 + random->nextInt(20); } else { yRotA = (random->nextFloat() - 0.5f) * 20; } }
if (lookingAt != NULL) { lookAt(lookingAt, 10.0f, (float) getMaxHeadXRot()); if (lookTime-- <= 0 || lookingAt->removed || lookingAt->distanceToSqr(shared_from_this()) > lookDistance * lookDistance) { lookingAt = nullptr; } } else { if (random->nextFloat() < 0.05f) { yRotA = (random->nextFloat() - 0.5f) * 20; } yRot += yRotA; xRot = defaultLookAngle; }
bool inWater = isInWater(); bool inLava = isInLava(); if (inWater || inLava) jumping = random->nextFloat() < 0.8f;}
int Mob::getMaxHeadXRot() { return 40;}
void Mob::lookAt(shared_ptr<Entity> e, float yMax, float xMax) { double xd = e->x - x; double yd; double zd = e->z - z;
if ( e->instanceof(eTYPE_LIVINGENTITY) ) { shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(e); yd = (mob->y + mob->getHeadHeight()) - (y + getHeadHeight()); } else { yd = (e->bb->y0 + e->bb->y1) / 2 - (y + getHeadHeight()); }
double sd = Mth::sqrt(xd * xd + zd * zd);
float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; float xRotD = (float) -(atan2(yd, sd) * 180 / PI); xRot = rotlerp(xRot, xRotD, xMax); yRot = rotlerp(yRot, yRotD, yMax);}
bool Mob::isLookingAtAnEntity() { return lookingAt != NULL;}
shared_ptr<Entity> Mob::getLookingAt() { return lookingAt;}
float Mob::rotlerp(float a, float b, float max) { float diff = Mth::wrapDegrees(b - a); if (diff > max) { diff = max; } if (diff < -max) { diff = -max; } return a + diff;}
bool Mob::canSpawn() { // 4J - altered to use special containsAnyLiquid variant return level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid_NoLoad(bb);}
float Mob::getSizeScale(){ return 1.0f;}
float Mob::getHeadSizeScale(){ return 1.0f;}
int Mob::getMaxSpawnClusterSize() { return 4;}
int Mob::getMaxFallDistance(){ if (getTarget() == NULL) return 3; int sacrifice = (int) (getHealth() - (getMaxHealth() * 0.33f)); sacrifice -= (3 - level->difficulty) * 4; if (sacrifice < 0) sacrifice = 0; return sacrifice + 3;}
shared_ptr<ItemInstance> Mob::getCarriedItem(){ return equipment[SLOT_WEAPON];}
shared_ptr<ItemInstance> Mob::getCarried(int slot){ return equipment[slot];}
shared_ptr<ItemInstance> Mob::getArmor(int pos){ return equipment[pos + 1];}
void Mob::setEquippedSlot(int slot, shared_ptr<ItemInstance> item){ equipment[slot] = item;}
ItemInstanceArray Mob::getEquipmentSlots(){ return equipment;}
void Mob::dropEquipment(bool byPlayer, int playerBonusLevel){ for (int slot = 0; slot < getEquipmentSlots().length; slot++) { shared_ptr<ItemInstance> item = getCarried(slot); bool preserve = dropChances[slot] > 1;
if (item != NULL && (byPlayer || preserve) && random->nextFloat() - playerBonusLevel * 0.01f < dropChances[slot]) { if (!preserve && item->isDamageableItem()) { int _max = max(item->getMaxDamage() - 25, 1); int damage = item->getMaxDamage() - random->nextInt(random->nextInt(_max) + 1); if (damage > _max) damage = _max; if (damage < 1) damage = 1; item->setAuxValue(damage); } spawnAtLocation(item, 0); } }}
void Mob::populateDefaultEquipmentSlots(){ if (random->nextFloat() < MAX_WEARING_ARMOR_CHANCE * level->getDifficulty(x, y, z)) { int armorType = random->nextInt(2); float partialChance = level->difficulty == Difficulty::HARD ? 0.1f : 0.25f; if (random->nextFloat() < 0.095f) armorType++; if (random->nextFloat() < 0.095f) armorType++; if (random->nextFloat() < 0.095f) armorType++;
for (int i = 3; i >= 0; i--) { shared_ptr<ItemInstance> item = getArmor(i); if (i < 3 && random->nextFloat() < partialChance) break; if (item == NULL) { Item *equip = getEquipmentForSlot(i + 1, armorType); if (equip != NULL) setEquippedSlot(i + 1, shared_ptr<ItemInstance>(new ItemInstance(equip))); } } }}
int Mob::getEquipmentSlotForItem(shared_ptr<ItemInstance> item){ if (item->id == Tile::pumpkin_Id || item->id == Item::skull_Id) { return SLOT_HELM; }
ArmorItem *armorItem = dynamic_cast<ArmorItem *>(item->getItem()); if (armorItem != NULL) { switch (armorItem->slot) { case ArmorItem::SLOT_FEET: return SLOT_BOOTS; case ArmorItem::SLOT_LEGS: return SLOT_LEGGINGS; case ArmorItem::SLOT_TORSO: return SLOT_CHEST; case ArmorItem::SLOT_HEAD: return SLOT_HELM; } }
return SLOT_WEAPON;}
Item *Mob::getEquipmentForSlot(int slot, int type){ switch (slot) { case SLOT_HELM: if (type == 0) return Item::helmet_leather; if (type == 1) return Item::helmet_gold; if (type == 2) return Item::helmet_chain; if (type == 3) return Item::helmet_iron; if (type == 4) return Item::helmet_diamond; case SLOT_CHEST: if (type == 0) return Item::chestplate_leather; if (type == 1) return Item::chestplate_gold; if (type == 2) return Item::chestplate_chain; if (type == 3) return Item::chestplate_iron; if (type == 4) return Item::chestplate_diamond; case SLOT_LEGGINGS: if (type == 0) return Item::leggings_leather; if (type == 1) return Item::leggings_gold; if (type == 2) return Item::leggings_chain; if (type == 3) return Item::leggings_iron; if (type == 4) return Item::leggings_diamond; case SLOT_BOOTS: if (type == 0) return Item::boots_leather; if (type == 1) return Item::boots_gold; if (type == 2) return Item::boots_chain; if (type == 3) return Item::boots_iron; if (type == 4) return Item::boots_diamond; }
return NULL;}
void Mob::populateDefaultEquipmentEnchantments(){ float difficulty = level->getDifficulty(x, y, z);
if (getCarriedItem() != NULL && random->nextFloat() < MAX_ENCHANTED_WEAPON_CHANCE * difficulty) { EnchantmentHelper::enchantItem(random, getCarriedItem(), (int) (5 + difficulty * random->nextInt(18))); }
for (int i = 0; i < 4; i++) { shared_ptr<ItemInstance> item = getArmor(i); if (item != NULL && random->nextFloat() < MAX_ENCHANTED_ARMOR_CHANCE * difficulty) { EnchantmentHelper::enchantItem(random, item, (int) (5 + difficulty * random->nextInt(18))); } }}
/*** Added this method so mobs can handle their own spawn settings instead of* hacking MobSpawner.java* * @param groupData* TODO* @return TODO*/MobGroupData *Mob::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param{ // 4J Stu - Take this out, it's not great and nobody will notice. Also not great for performance. //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->addModifier(new AttributeModifier(random->nextGaussian() * 0.05, AttributeModifier::OPERATION_MULTIPLY_BASE));
return groupData;}
void Mob::finalizeSpawnEggSpawn(int extraData){}
bool Mob::canBeControlledByRider(){ return false;}
wstring Mob::getAName(){ if (hasCustomName()) return getCustomName(); return LivingEntity::getAName();}
void Mob::setPersistenceRequired(){ persistenceRequired = true;}
void Mob::setCustomName(const wstring &name){ entityData->set(DATA_CUSTOM_NAME, name);}
wstring Mob::getCustomName(){ return entityData->getString(DATA_CUSTOM_NAME);}
bool Mob::hasCustomName(){ return entityData->getString(DATA_CUSTOM_NAME).length() > 0;}
void Mob::setCustomNameVisible(bool visible){ entityData->set(DATA_CUSTOM_NAME_VISIBLE, visible ? (byte) 1 : (byte) 0);}
bool Mob::isCustomNameVisible(){ return entityData->getByte(DATA_CUSTOM_NAME_VISIBLE) == 1;}
bool Mob::shouldShowName(){ return isCustomNameVisible();}
void Mob::setDropChance(int slot, float pct){ dropChances[slot] = pct;}
bool Mob::canPickUpLoot(){ return _canPickUpLoot;}
void Mob::setCanPickUpLoot(bool canPickUpLoot){ _canPickUpLoot = canPickUpLoot;}
bool Mob::isPersistenceRequired(){ return persistenceRequired;}
bool Mob::interact(shared_ptr<Player> player){
if (isLeashed() && getLeashHolder() == player) { dropLeash(true, !player->abilities.instabuild); return true; }
shared_ptr<ItemInstance> itemstack = player->inventory->getSelected(); if (itemstack != NULL) { // it's inconvenient to have the leash code here, but it's because // the mob.interact(player) method has priority over // item.interact(mob) if (itemstack->id == Item::lead_Id) { if (canBeLeashed()) { shared_ptr<TamableAnimal> tamableAnimal = nullptr; if ( shared_from_this()->instanceof(eTYPE_TAMABLE_ANIMAL) && (tamableAnimal = dynamic_pointer_cast<TamableAnimal>(shared_from_this()))->isTame() ) // 4J-JEV: excuse the assignment operator in here, don't want to dyn-cast if it's avoidable. { if (player->getUUID().compare(tamableAnimal->getOwnerUUID()) == 0) { setLeashedTo(player, true); itemstack->count--; return true; } } else { setLeashedTo(player, true); itemstack->count--; return true; } } } }
if (mobInteract(player)) { return true; }
return LivingEntity::interact(player);}
bool Mob::mobInteract(shared_ptr<Player> player){ return false;}
void Mob::tickLeash(){ if (leashInfoTag != NULL) { restoreLeashFromSave(); } if (!_isLeashed) { return; }
if (leashHolder == NULL || leashHolder->removed) { dropLeash(true, true); return; }}
void Mob::dropLeash(bool synch, bool createItemDrop){ if (_isLeashed) { _isLeashed = false; leashHolder = nullptr; if (!level->isClientSide && createItemDrop) { spawnAtLocation(Item::lead_Id, 1); }
ServerLevel *serverLevel = dynamic_cast<ServerLevel *>(level); if (!level->isClientSide && synch && serverLevel != NULL) { serverLevel->getTracker()->broadcast(shared_from_this(), shared_ptr<SetEntityLinkPacket>(new SetEntityLinkPacket(SetEntityLinkPacket::LEASH, shared_from_this(), nullptr))); } }}
bool Mob::canBeLeashed(){ return !isLeashed() && !shared_from_this()->instanceof(eTYPE_ENEMY);}
bool Mob::isLeashed(){ return _isLeashed;}
shared_ptr<Entity> Mob::getLeashHolder(){ return leashHolder;}
void Mob::setLeashedTo(shared_ptr<Entity> holder, bool synch){ _isLeashed = true; leashHolder = holder; ServerLevel *serverLevel = dynamic_cast<ServerLevel *>(level); if (!level->isClientSide && synch && serverLevel) { serverLevel->getTracker()->broadcast(shared_from_this(), shared_ptr<SetEntityLinkPacket>( new SetEntityLinkPacket(SetEntityLinkPacket::LEASH, shared_from_this(), leashHolder))); }}
void Mob::restoreLeashFromSave(){ // after being added to the world, attempt to recreate leash bond if (_isLeashed && leashInfoTag != NULL) { if (leashInfoTag->contains(L"UUID")) { wstring leashUuid = leashInfoTag->getString(L"UUID"); vector<shared_ptr<Entity> > *livingEnts = level->getEntitiesOfClass(typeid(LivingEntity), bb->grow(10, 10, 10)); for(AUTO_VAR(it, livingEnts->begin()); it != livingEnts->end(); ++it) { shared_ptr<LivingEntity> le = dynamic_pointer_cast<LivingEntity>(*it); if (le->getUUID().compare(leashUuid) == 0) { leashHolder = le; setLeashedTo(leashHolder, true); break; } } delete livingEnts; } else if (leashInfoTag->contains(L"X") && leashInfoTag->contains(L"Y") && leashInfoTag->contains(L"Z")) { int x = leashInfoTag->getInt(L"X"); int y = leashInfoTag->getInt(L"Y"); int z = leashInfoTag->getInt(L"Z");
shared_ptr<LeashFenceKnotEntity> activeKnot = LeashFenceKnotEntity::findKnotAt(level, x, y, z); if (activeKnot == NULL) { activeKnot = LeashFenceKnotEntity::createAndAddKnot(level, x, y, z); } leashHolder = activeKnot; setLeashedTo(leashHolder, true); } else { dropLeash(false, true); } } leashInfoTag = NULL;}
// 4J added so we can not render mobs before their chunks are loaded - to resolve bug 10327 :Gameplay: NPCs can spawn over chunks that have not yet been streamed and display jitter.bool Mob::shouldRender(Vec3 *c){ if( !level->reallyHasChunksAt( Mth::floor(bb->x0), Mth::floor(bb->y0), Mth::floor(bb->z0), Mth::floor(bb->x1), Mth::floor(bb->y1), Mth::floor(bb->z1))) { return false; } return Entity::shouldRender(c);}
void Mob::setLevel(Level *level){ Entity::setLevel(level); navigation->setLevel(level); goalSelector.setLevel(level); targetSelector.setLevel(level);}