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.
40 kB · 1841 lines
C++
at master
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841#include "stdafx.h"#include "net.minecraft.world.entity.h"#include "net.minecraft.world.entity.monster.h"#include "net.minecraft.world.entity.ai.attributes.h"#include "net.minecraft.world.entity.ai.goal.h"#include "net.minecraft.world.entity.ai.navigation.h"#include "net.minecraft.world.entity.player.h"#include "net.minecraft.world.entity.monster.h"#include "net.minecraft.world.effect.h"#include "net.minecraft.world.damagesource.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.level.h"#include "net.minecraft.world.level.tile.h"#include "net.minecraft.world.inventory.h"#include "net.minecraft.world.phys.h"#include "..\Minecraft.Client\Textures.h"#include "..\Minecraft.Client\Minecraft.h"#include "BasicTypeContainers.h"#include "EntityHorse.h"
const wstring EntityHorse::TEX_FOLDER = L"mob/horse/";
const EntitySelector *EntityHorse::PARENT_HORSE_SELECTOR = new HorseEntitySelector();
Attribute *EntityHorse::JUMP_STRENGTH = (new RangedAttribute(eAttributeId_HORSE_JUMPSTRENGTH, .7, 0, 2.0))->setSyncable(true);
wstring EntityHorse::ARMOR_TEXTURES[EntityHorse::ARMORS] = {L"", L"armor/horse_armor_iron.png", L"armor/horse_armor_gold.png", L"armor/horse_armor_diamond.png"};int EntityHorse::ARMOR_TEXTURES_ID[EntityHorse::ARMORS] = {-1, TN_MOB_HORSE_ARMOR_IRON, TN_MOB_HORSE_ARMOR_GOLD, TN_MOB_HORSE_ARMOR_DIAMOND };wstring EntityHorse::ARMOR_HASHES[EntityHorse::ARMORS] = {L"", L"meo", L"goo", L"dio"};int EntityHorse::ARMOR_PROTECTION[EntityHorse::ARMORS] = {0, 5, 7, 11};
wstring EntityHorse::VARIANT_TEXTURES[EntityHorse::VARIANTS] = {L"horse_white.png", L"horse_creamy.png", L"horse_chestnut.png", L"horse_brown.png", L"horse_black.png", L"horse_gray.png", L"horse_darkbrown.png"};int EntityHorse::VARIANT_TEXTURES_ID[EntityHorse::VARIANTS] = {TN_MOB_HORSE_WHITE, TN_MOB_HORSE_CREAMY, TN_MOB_HORSE_CHESTNUT, TN_MOB_HORSE_BROWN, TN_MOB_HORSE_BLACK, TN_MOB_HORSE_GRAY, TN_MOB_HORSE_DARKBROWN};
wstring EntityHorse::VARIANT_HASHES[EntityHorse::VARIANTS] = {L"hwh", L"hcr", L"hch", L"hbr", L"hbl", L"hgr", L"hdb"};
wstring EntityHorse::MARKING_TEXTURES[EntityHorse::MARKINGS] = {L"", L"horse_markings_white.png", L"horse_markings_whitefield.png", L"horse_markings_whitedots.png", L"horse_markings_blackdots.png"};int EntityHorse::MARKING_TEXTURES_ID[EntityHorse::MARKINGS] = {-1, TN_MOB_HORSE_MARKINGS_WHITE, TN_MOB_HORSE_MARKINGS_WHITEFIELD, TN_MOB_HORSE_MARKINGS_WHITEDOTS, TN_MOB_HORSE_MARKINGS_BLACKDOTS};wstring EntityHorse::MARKING_HASHES[EntityHorse::MARKINGS] = {L"", L"wo_", L"wmo", L"wdo", L"bdo"};
bool HorseEntitySelector::matches(shared_ptr<Entity> entity) const{ return entity->instanceof(eTYPE_HORSE) && dynamic_pointer_cast<EntityHorse>(entity)->isBred();}
EntityHorse::EntityHorse(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());
countEating = 0; mouthCounter = 0; standCounter = 0; tailCounter = 0; sprintCounter = 0; isEntityJumping = false; inventory = nullptr; hasReproduced = false; temper = 0; playerJumpPendingScale = 0.0f; allowStandSliding = false; eatAnim = eatAnimO = 0.0f; standAnim = standAnimO = 0.0f; mouthAnim = mouthAnimO = 0.0f; gallopSoundCounter = 0;
layerTextureHashName = L"";
layerTextureLayers = intArray(3); for(unsigned int i = 0; i < 3; ++i) { layerTextureLayers[i] = -1; }
setSize(1.4f, 1.6f); fireImmune = false; setChestedHorse(false);
getNavigation()->setAvoidWater(true); goalSelector.addGoal(0, new FloatGoal(this)); goalSelector.addGoal(1, new PanicGoal(this, 1.2)); goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2)); goalSelector.addGoal(2, new BreedGoal(this, 1.0)); goalSelector.addGoal(4, new FollowParentGoal(this, 1.0)); goalSelector.addGoal(6, new RandomStrollGoal(this, .7)); goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(8, new RandomLookAroundGoal(this));
createInventory();}
EntityHorse::~EntityHorse(){ delete [] layerTextureLayers.data;}
void EntityHorse::defineSynchedData(){ Animal::defineSynchedData(); entityData->define(DATA_ID_HORSE_FLAGS, 0); entityData->define(DATA_ID_TYPE, (byte) 0); entityData->define(DATA_ID_TYPE_VARIANT, 0); entityData->define(DATA_ID_OWNER_NAME, L""); entityData->define(DATA_ID_ARMOR, 0);}
void EntityHorse::setType(int i){ entityData->set(DATA_ID_TYPE, (byte) i); clearLayeredTextureInfo();}
int EntityHorse::getType(){ return entityData->getByte(DATA_ID_TYPE);}
void EntityHorse::setVariant(int i){ entityData->set(DATA_ID_TYPE_VARIANT, i); clearLayeredTextureInfo();}
int EntityHorse::getVariant(){ return entityData->getInteger(DATA_ID_TYPE_VARIANT);}
wstring EntityHorse::getAName(){ if (hasCustomName()) return getCustomName();#ifdef _DEBUG int type = getType(); switch (type) { default: case TYPE_HORSE: return L"entity.horse.name"; case TYPE_DONKEY: return L"entity.donkey.name"; case TYPE_MULE: return L"entity.mule.name"; case TYPE_SKELETON: return L"entity.skeletonhorse.name"; case TYPE_UNDEAD: return L"entity.zombiehorse.name"; }#else return L"";#endif}
bool EntityHorse::getHorseFlag(int flag){ return (entityData->getInteger(DATA_ID_HORSE_FLAGS) & flag) != 0;}
void EntityHorse::setHorseFlag(int flag, bool value){ int current = entityData->getInteger(DATA_ID_HORSE_FLAGS); if (value) { entityData->set(DATA_ID_HORSE_FLAGS, current | flag); } else { entityData->set(DATA_ID_HORSE_FLAGS, current & ~flag); }}
bool EntityHorse::isAdult(){ return !isBaby();}
bool EntityHorse::isTamed(){ return getHorseFlag(FLAG_TAME);}
bool EntityHorse::isRidable(){ return isAdult();}
wstring EntityHorse::getOwnerName(){ return entityData->getString(DATA_ID_OWNER_NAME);}
void EntityHorse::setOwner(const wstring &par1Str){ entityData->set(DATA_ID_OWNER_NAME, par1Str);}
float EntityHorse::getFoalScale(){ int age = getAge(); if (age >= 0) { return 1.0f; } return .5f + (float) (BABY_START_AGE - age) / (float) BABY_START_AGE * .5f;}
void EntityHorse::updateSize(bool isBaby){ if (isBaby) { internalSetSize(getFoalScale()); } else { internalSetSize(1.0f); }}
bool EntityHorse::getIsJumping(){ return isEntityJumping;}
void EntityHorse::setTamed(bool flag){ setHorseFlag(FLAG_TAME, flag);}
void EntityHorse::setIsJumping(bool flag){ isEntityJumping = flag;}
bool EntityHorse::canBeLeashed(){ return !isUndead() && Animal::canBeLeashed();}
void EntityHorse::onLeashDistance(float distanceToLeashHolder){ if (distanceToLeashHolder > 6 && isEating()) { setEating(false); }}
bool EntityHorse::isChestedHorse(){ return getHorseFlag(FLAG_CHESTED);}
int EntityHorse::getArmorType(){ return entityData->getInteger(DATA_ID_ARMOR);}
int EntityHorse::getArmorTypeForItem(shared_ptr<ItemInstance> armorItem){ if (armorItem == NULL) { return ARMOR_NONE; } if (armorItem->id == Item::horseArmorMetal_Id) { return ARMOR_IRON; } else if (armorItem->id == Item::horseArmorGold_Id) { return ARMOR_GOLD; } else if (armorItem->id == Item::horseArmorDiamond_Id) { return ARMOR_DIAMOND; } return ARMOR_NONE;}
bool EntityHorse::isEating(){ return getHorseFlag(FLAG_EATING);}
bool EntityHorse::isStanding(){ return getHorseFlag(FLAG_STANDING);}
bool EntityHorse::isBred(){ return getHorseFlag(FLAG_BRED);}
bool EntityHorse::getHasReproduced(){ return hasReproduced;}
void EntityHorse::setArmorType(int i){ entityData->set(DATA_ID_ARMOR, i); clearLayeredTextureInfo();}
void EntityHorse::setBred(bool flag){ setHorseFlag(FLAG_BRED, flag);
}
void EntityHorse::setChestedHorse(bool flag){ setHorseFlag(FLAG_CHESTED, flag);}
void EntityHorse::setReproduced(bool flag){ hasReproduced = flag;}
void EntityHorse::setSaddled(bool flag){ setHorseFlag(FLAG_SADDLE, flag);}
int EntityHorse::getTemper(){ return temper;}
void EntityHorse::setTemper(int temper){ this->temper = temper;}
int EntityHorse::modifyTemper(int amount){ int temper = Mth::clamp(getTemper() + amount, 0, getMaxTemper());
setTemper(temper); return temper;}
bool EntityHorse::hurt(DamageSource *damagesource, float dmg){ // 4J: Protect owned horses from untrusted players if (isTamed()) { shared_ptr<Entity> entity = damagesource->getDirectEntity(); if (entity != NULL && entity->instanceof(eTYPE_PLAYER)) { shared_ptr<Player> attacker = dynamic_pointer_cast<Player>(entity); attacker->canHarmPlayer(getOwnerName()); } }
shared_ptr<Entity> attacker = damagesource->getEntity(); if (rider.lock() != NULL && (rider.lock() == (attacker) )) { return false; }
return Animal::hurt(damagesource, dmg);}
int EntityHorse::getArmorValue(){ return ARMOR_PROTECTION[getArmorType()];}
bool EntityHorse::isPushable(){ return rider.lock() == NULL;}
// TODO: [EB]: Explain why this is being done - what side effect does getBiome have?bool EntityHorse::checkSpawningBiome(){ int x = Mth::floor(this->x); int z = Mth::floor(this->z);
level->getBiome(x, z); return true;}
/*** Drops a chest block if the horse is bagged*/void EntityHorse::dropBags(){ if (level->isClientSide || !isChestedHorse()) { return; }
spawnAtLocation(Tile::chest_Id, 1); setChestedHorse(false);}
void EntityHorse::eatingHorse(){ openMouth(); level->playEntitySound(shared_from_this(), eSoundType_EATING, 1.0f, 1.0f + (random->nextFloat() - random->nextFloat()) * 0.2f);}
/*** Changed to adjust fall damage for riders*/void EntityHorse::causeFallDamage(float fallDistance){
if (fallDistance > 1) { playSound(eSoundType_MOB_HORSE_LAND, .4f, 1); }
int dmg = Mth::ceil(fallDistance * .5f - 3.0f); if (dmg <= 0) return;
hurt(DamageSource::fall, dmg);
if (rider.lock() != NULL) { rider.lock()->hurt(DamageSource::fall, dmg); }
int id = level->getTile(Mth::floor(x), Mth::floor(y - 0.2 - yRotO), Mth::floor(z)); if (id > 0) { const Tile::SoundType *stepsound = Tile::tiles[id]->soundType; level->playEntitySound(shared_from_this(), stepsound->getStepSound(), stepsound->getVolume() * 0.5f, stepsound->getPitch() * 0.75f); }}
/*** Different inventory sizes depending on the kind of horse* * @return*/int EntityHorse::getInventorySize(){ int type = getType(); if (isChestedHorse() && (type == TYPE_DONKEY || type == TYPE_MULE)) { return INV_BASE_COUNT + INV_DONKEY_CHEST_COUNT; } return INV_BASE_COUNT;}
void EntityHorse::createInventory(){ shared_ptr<AnimalChest> old = inventory; inventory = shared_ptr<AnimalChest>( new AnimalChest(L"HorseChest", getInventorySize()) ); inventory->setCustomName(getAName()); if (old != NULL) { old->removeListener(this);
int max = min(old->getContainerSize(), inventory->getContainerSize()); for (int slot = 0; slot < max; slot++) { shared_ptr<ItemInstance> item = old->getItem(slot); if (item != NULL) { inventory->setItem(slot, item->copy()); } } old = nullptr; } inventory->addListener(this); updateEquipment();}
void EntityHorse::updateEquipment(){ if (!level->isClientSide) { setSaddled(inventory->getItem(INV_SLOT_SADDLE) != NULL); if (canWearArmor()) { setArmorType(getArmorTypeForItem(inventory->getItem(INV_SLOT_ARMOR))); } }}
void EntityHorse::containerChanged(){ int armorType = getArmorType(); bool saddled = isSaddled(); updateEquipment(); if (tickCount > 20) { if (armorType == ARMOR_NONE && armorType != getArmorType()) { playSound(eSoundType_MOB_HORSE_ARMOR, .5f, 1); } if (!saddled && isSaddled()) { playSound(eSoundType_MOB_HORSE_LEATHER, .5f, 1); } }
}
bool EntityHorse::canSpawn(){ checkSpawningBiome(); return Animal::canSpawn();}
shared_ptr<EntityHorse> EntityHorse::getClosestMommy(shared_ptr<Entity> baby, double searchRadius){ double closestDistance = Double::MAX_VALUE;
shared_ptr<Entity> mommy = nullptr; vector<shared_ptr<Entity> > *list = level->getEntities(baby, baby->bb->expand(searchRadius, searchRadius, searchRadius), PARENT_HORSE_SELECTOR);
for(AUTO_VAR(it,list->begin()); it != list->end(); ++it) { shared_ptr<Entity> horse = *it; double distanceSquared = horse->distanceToSqr(baby->x, baby->y, baby->z);
if (distanceSquared < closestDistance) { mommy = horse; closestDistance = distanceSquared; } } delete list;
return dynamic_pointer_cast<EntityHorse>(mommy);}
double EntityHorse::getCustomJump(){ return getAttribute(JUMP_STRENGTH)->getValue();}
int EntityHorse::getDeathSound(){ openMouth(); int type = getType(); if (type == TYPE_UNDEAD) { return eSoundType_MOB_HORSE_ZOMBIE_DEATH; //"mob.horse.zombie.death"; } if (type == TYPE_SKELETON) { return eSoundType_MOB_HORSE_SKELETON_DEATH; //"mob.horse.skeleton.death"; } if (type == TYPE_DONKEY || type == TYPE_MULE) { return eSoundType_MOB_HORSE_DONKEY_DEATH; //"mob.horse.donkey.death"; } return eSoundType_MOB_HORSE_DEATH; //"mob.horse.death";}
int EntityHorse::getDeathLoot(){ bool flag = random->nextInt(4) == 0;
int type = getType(); if (type == TYPE_SKELETON) { return Item::bone_Id; } if (type == TYPE_UNDEAD) { if (flag) { return 0; } return Item::rotten_flesh_Id; }
return Item::leather_Id;}
int EntityHorse::getHurtSound(){ openMouth(); { if (random->nextInt(3) == 0) { stand(); } } int type = getType(); if (type == TYPE_UNDEAD) { return eSoundType_MOB_HORSE_ZOMBIE_HIT; //"mob.horse.zombie.hit"; } if (type == TYPE_SKELETON) { return eSoundType_MOB_HORSE_SKELETON_HIT; //"mob.horse.skeleton.hit"; } if (type == TYPE_DONKEY || type == TYPE_MULE) { return eSoundType_MOB_HORSE_DONKEY_HIT; //"mob.horse.donkey.hit"; } return eSoundType_MOB_HORSE_HIT; //"mob.horse.hit";}
bool EntityHorse::isSaddled(){ return getHorseFlag(FLAG_SADDLE);}
int EntityHorse::getAmbientSound(){ openMouth(); if (random->nextInt(10) == 0 && !isImmobile()) { stand(); } int type = getType(); if (type == TYPE_UNDEAD) { return eSoundType_MOB_HORSE_ZOMBIE_IDLE; //"mob.horse.zombie.idle"; } if (type == TYPE_SKELETON) { return eSoundType_MOB_HORSE_SKELETON_IDLE; //"mob.horse.skeleton.idle"; } if (type == TYPE_DONKEY || type == TYPE_MULE) { return eSoundType_MOB_HORSE_DONKEY_IDLE; //"mob.horse.donkey.idle"; } return eSoundType_MOB_HORSE_IDLE; //"mob.horse.idle";}
/*** sound played when an untamed mount buckles rider*/int EntityHorse::getMadSound(){ openMouth(); stand(); int type = getType(); if (type == TYPE_UNDEAD || type == TYPE_SKELETON) { return -1; } if (type == TYPE_DONKEY || type == TYPE_MULE) { return eSoundType_MOB_HORSE_DONKEY_ANGRY; //"mob.horse.donkey.angry"; } return eSoundType_MOB_HORSE_ANGRY; //"mob.horse.angry";}
void EntityHorse::playStepSound(int xt, int yt, int zt, int t){ const Tile::SoundType *soundType = Tile::tiles[t]->soundType; if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) { soundType = Tile::topSnow->soundType; } if (!Tile::tiles[t]->material->isLiquid()) { int type = getType(); if (rider.lock() != NULL && type != TYPE_DONKEY && type != TYPE_MULE) { gallopSoundCounter++; if (gallopSoundCounter > 5 && gallopSoundCounter % 3 == 0) { playSound(eSoundType_MOB_HORSE_GALLOP, soundType->getVolume() * 0.15f, soundType->getPitch()); if (type == TYPE_HORSE && random->nextInt(10) == 0) { playSound(eSoundType_MOB_HORSE_BREATHE, soundType->getVolume() * 0.6f, soundType->getPitch()); } } else if (gallopSoundCounter <= 5) { playSound(eSoundType_MOB_HORSE_WOOD, soundType->getVolume() * 0.15f, soundType->getPitch()); } } else if (soundType == Tile::SOUND_WOOD) { playSound(eSoundType_MOB_HORSE_SOFT, soundType->getVolume() * 0.15f, soundType->getPitch()); } else { playSound(eSoundType_MOB_HORSE_WOOD, soundType->getVolume() * 0.15f, soundType->getPitch()); } }}
void EntityHorse::registerAttributes(){ Animal::registerAttributes();
getAttributes()->registerAttribute(JUMP_STRENGTH);
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(53); getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.225f);}
int EntityHorse::getMaxSpawnClusterSize(){ return 6;}
/*** How difficult is the creature to be tamed? the Higher the number, the* more difficult*/int EntityHorse::getMaxTemper(){ return 100;}
float EntityHorse::getSoundVolume(){ return 0.8f;}
int EntityHorse::getAmbientSoundInterval(){ return 400;}
bool EntityHorse::hasLayeredTextures(){ return getType() == TYPE_HORSE || getArmorType() > 0;}
void EntityHorse::clearLayeredTextureInfo(){ layerTextureHashName = L"";}
void EntityHorse::rebuildLayeredTextureInfo(){ layerTextureHashName = L"horse/"; layerTextureLayers[0] = -1; layerTextureLayers[1] = -1; layerTextureLayers[2] = -1;
int type = getType(); int variant = getVariant(); int armorIndex = 2; if (type == TYPE_HORSE) { int skin = variant & 0xFF; int markings = (variant & 0xFF00) >> 8; layerTextureLayers[0] = VARIANT_TEXTURES_ID[skin]; layerTextureHashName += VARIANT_HASHES[skin];
layerTextureLayers[1] = MARKING_TEXTURES_ID[markings]; layerTextureHashName += MARKING_HASHES[markings];
if(layerTextureLayers[1] == -1) { armorIndex = 1; } } else { layerTextureLayers[0] = -1; layerTextureHashName += L"_" + _toString<int>(type) + L"_"; armorIndex = 1; }
int armor = getArmorType(); layerTextureLayers[armorIndex] = ARMOR_TEXTURES_ID[armor]; layerTextureHashName += ARMOR_HASHES[armor];}
wstring EntityHorse::getLayeredTextureHashName(){ if (layerTextureHashName.empty()) { rebuildLayeredTextureInfo(); } return layerTextureHashName;}
intArray EntityHorse::getLayeredTextureLayers(){ if (layerTextureHashName.empty()) { rebuildLayeredTextureInfo(); } return layerTextureLayers;}
void EntityHorse::openInventory(shared_ptr<Player> player){ if (!level->isClientSide && (rider.lock() == NULL || rider.lock() == player) && isTamed()) { inventory->setCustomName(getAName()); player->openHorseInventory(dynamic_pointer_cast<EntityHorse>(shared_from_this()), inventory); }}
bool EntityHorse::mobInteract(shared_ptr<Player> player){ shared_ptr<ItemInstance> itemstack = player->inventory->getSelected();
if (itemstack != NULL && itemstack->id == Item::spawnEgg_Id) { return Animal::mobInteract(player); }
if (!isTamed()) { if (isUndead()) { return false; } }
if (isTamed() && isAdult() && player->isSneaking()) { openInventory(player); return true; }
if (isRidable() && rider.lock() != NULL) { return Animal::mobInteract(player); }
// consumables if (itemstack != NULL) { bool itemUsed = false;
if (canWearArmor()) { int armorType = -1;
if (itemstack->id == Item::horseArmorMetal_Id) { armorType = ARMOR_IRON; } else if (itemstack->id == Item::horseArmorGold_Id) { armorType = ARMOR_GOLD; } else if (itemstack->id == Item::horseArmorDiamond_Id) { armorType = ARMOR_DIAMOND; }
if (armorType >= 0) { if (!isTamed()) { makeMad(); return true; } openInventory(player); return true; } }
if (!itemUsed && !isUndead()) { float _heal = 0; int _ageUp = 0; int temper = 0;
if (itemstack->id == Item::wheat_Id) { _heal = 2; _ageUp = 60; temper = 3; } else if (itemstack->id == Item::sugar_Id) { _heal = 1; _ageUp = 30; temper = 3; } else if (itemstack->id == Item::bread_Id) { _heal = 7; _ageUp = 180; temper = 3; } else if (itemstack->id == Tile::hayBlock_Id) { _heal = 20; _ageUp = 180; } else if (itemstack->id == Item::apple_Id) { _heal = 3; _ageUp = 60; temper = 3; } else if (itemstack->id == Item::carrotGolden_Id) { _heal = 4; _ageUp = 60; temper = 5; if (isTamed() && getAge() == 0) { itemUsed = true; setInLove(); } } else if (itemstack->id == Item::apple_gold_Id) { _heal = 10; _ageUp = 240; temper = 10; if (isTamed() && getAge() == 0) { itemUsed = true; setInLove(); } } if (getHealth() < getMaxHealth() && _heal > 0) { heal(_heal); itemUsed = true; } if (!isAdult() && _ageUp > 0) { ageUp(_ageUp); itemUsed = true; } if (temper > 0 && (itemUsed || !isTamed()) && temper < getMaxTemper()) { itemUsed = true; modifyTemper(temper); } if (itemUsed) { eatingHorse(); } }
if (!isTamed() && !itemUsed) { if (itemstack != NULL && itemstack->interactEnemy(player, dynamic_pointer_cast<LivingEntity>(shared_from_this()))) { return true; } makeMad(); return true; }
if (!itemUsed && canWearBags() && !isChestedHorse()) { if (itemstack->id == Tile::chest_Id) { setChestedHorse(true); playSound(eSoundType_MOB_CHICKENPLOP, 1.0f, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); itemUsed = true; createInventory(); } }
if (!itemUsed && isRidable() && !isSaddled()) { if (itemstack->id == Item::saddle_Id) { openInventory(player); return true; } }
if (itemUsed) { if (!player->abilities.instabuild) { if (--itemstack->count == 0) { player->inventory->setItem(player->inventory->selected, nullptr); } } return true; } }
if (isRidable() && rider.lock() == NULL) { // for name tag items and such, we must call the item's interaction // method before riding if (itemstack != NULL && itemstack->interactEnemy(player, dynamic_pointer_cast<LivingEntity>(shared_from_this()))) { return true; } doPlayerRide(player);
app.DebugPrintf("<EntityHorse::mobInteract> Horse speed: %f\n", (float) (getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue()));
return true; } else { return Animal::mobInteract(player); }}
void EntityHorse::doPlayerRide(shared_ptr<Player> player){ player->yRot = yRot; player->xRot = xRot; setEating(false); setStanding(false); if (!level->isClientSide) { player->ride(shared_from_this()); }}
/*** Can this horse be trapped in an amulet?*/bool EntityHorse::isAmuletHorse(){ return getType() == TYPE_SKELETON;}
/*** Can wear regular armor*/bool EntityHorse::canWearArmor(){ return getType() == TYPE_HORSE;}
/*** able to carry bags* * @return*/bool EntityHorse::canWearBags(){ int type = getType(); return type == TYPE_MULE || type == TYPE_DONKEY;}
bool EntityHorse::isImmobile(){ if (rider.lock() != NULL && isSaddled()) { return true; } return isEating() || isStanding();}
/*** Rare horse that can be transformed into Nightmares or Bathorses or give* ghost horses on dead*/bool EntityHorse::isPureBreed(){ return getType() > 10 && getType() < 21;}
/*** Is this an Undead Horse?* * @return*/bool EntityHorse::isUndead(){ int type = getType(); return type == TYPE_UNDEAD || type == TYPE_SKELETON;}
bool EntityHorse::isSterile(){ return isUndead() || getType() == TYPE_MULE;}
bool EntityHorse::isFood(shared_ptr<ItemInstance> itemInstance){ // horses have their own food behaviors in mobInterract return false;}
void EntityHorse::moveTail(){ tailCounter = 1;}
int EntityHorse::nameYOffset(){ if (isAdult()) { return -80; } else { return (int) (-5 - getFoalScale() * 80.0f); }}
void EntityHorse::die(DamageSource *damagesource){ Animal::die(damagesource); if (!level->isClientSide) { dropMyStuff(); }}
void EntityHorse::aiStep(){ if (random->nextInt(200) == 0) { moveTail(); }
Animal::aiStep();
if (!level->isClientSide) { if (random->nextInt(900) == 0 && deathTime == 0) { heal(1); }
if (!isEating() && rider.lock() == NULL && random->nextInt(300) == 0) { if (level->getTile(Mth::floor(x), Mth::floor(y) - 1, Mth::floor(z)) == Tile::grass_Id) { setEating(true); } }
if (isEating() && ++countEating > 50) { countEating = 0; setEating(false); }
if (isBred() && !isAdult() && !isEating()) { shared_ptr<EntityHorse> mommy = getClosestMommy(shared_from_this(), 16); if (mommy != NULL && distanceToSqr(mommy) > 4.0) { Path *pathentity = level->findPath(shared_from_this(), mommy, 16.0f, true, false, false, true); setPath(pathentity); }
} }}
void EntityHorse::tick(){ Animal::tick();
// if client-side data values have changed, rebuild texture info if (level->isClientSide && entityData->isDirty()) { entityData->clearDirty(); clearLayeredTextureInfo(); }
if (mouthCounter > 0 && ++mouthCounter > 30) { mouthCounter = 0; setHorseFlag(FLAG_OPEN_MOUTH, false); }
if (!level->isClientSide) { if (standCounter > 0 && ++standCounter > 20) { standCounter = 0; setStanding(false); } }
if (tailCounter > 0 && ++tailCounter > 8) { tailCounter = 0; }
if (sprintCounter > 0) { ++sprintCounter;
if (sprintCounter > 300) { sprintCounter = 0; } }
eatAnimO = eatAnim; if (isEating()) { eatAnim += (1.0f - eatAnim) * .4f + .05f; if (eatAnim > 1) { eatAnim = 1; } } else { eatAnim += (.0f - eatAnim) * .4f - .05f; if (eatAnim < 0) { eatAnim = 0; } } standAnimO = standAnim; if (isStanding()) { // standing is incompatible with eating, so lock eat anim eatAnimO = eatAnim = 0; standAnim += (1.0f - standAnim) * .4f + .05f; if (standAnim > 1) { standAnim = 1; } } else { allowStandSliding = false; // the animation falling back to ground is slower in the beginning standAnim += (.8f * standAnim * standAnim * standAnim - standAnim) * .6f - .05f; if (standAnim < 0) { standAnim = 0; } } mouthAnimO = mouthAnim; if (getHorseFlag(FLAG_OPEN_MOUTH)) { mouthAnim += (1.0f - mouthAnim) * .7f + .05f; if (mouthAnim > 1) { mouthAnim = 1; } } else { mouthAnim += (.0f - mouthAnim) * .7f - .05f; if (mouthAnim < 0) { mouthAnim = 0; } }}
void EntityHorse::openMouth(){ if (!level->isClientSide) { mouthCounter = 1; setHorseFlag(FLAG_OPEN_MOUTH, true); }}
bool EntityHorse::isReadyForParenting(){ return rider.lock() == NULL && riding == NULL && isTamed() && isAdult() && !isSterile() && getHealth() >= getMaxHealth();}
bool EntityHorse::renderName(){ return hasCustomName() && rider.lock() == NULL;}
bool EntityHorse::rideableEntity(){ return true;}
void EntityHorse::setUsingItemFlag(bool flag){ setHorseFlag(FLAG_EATING, flag);}
void EntityHorse::setEating(bool state){ setUsingItemFlag(state);}
void EntityHorse::setStanding(bool state){ if (state) { setEating(false); } setHorseFlag(FLAG_STANDING, state);}
void EntityHorse::stand(){ if (!level->isClientSide) { standCounter = 1; setStanding(true); }}
void EntityHorse::makeMad(){ stand(); int ambient = getMadSound(); playSound(ambient, getSoundVolume(), getVoicePitch());}
void EntityHorse::dropMyStuff(){ dropInventory(shared_from_this(), inventory); dropBags();}
void EntityHorse::dropInventory(shared_ptr<Entity> entity, shared_ptr<AnimalChest> animalchest){ if (animalchest == NULL || level->isClientSide) return;
for (int i = 0; i < animalchest->getContainerSize(); i++) { shared_ptr<ItemInstance> itemstack = animalchest->getItem(i); if (itemstack == NULL) { continue; } spawnAtLocation(itemstack, 0); }
}
bool EntityHorse::tameWithName(shared_ptr<Player> player){ setOwner(player->getName()); setTamed(true); return true;}
/*** Overridden method to add control to mounts, should be moved to* EntityLiving*/void EntityHorse::travel(float xa, float ya){ // If the entity is not ridden by Player, then execute the normal // Entityliving code if (rider.lock() == NULL || !isSaddled()) { footSize = .5f; flyingSpeed = .02f; Animal::travel(xa, ya); return; }
yRotO = yRot = rider.lock()->yRot; xRot = rider.lock()->xRot * 0.5f; setRot(yRot, xRot); yHeadRot = yBodyRot = yRot;
shared_ptr<LivingEntity> livingRider = dynamic_pointer_cast<LivingEntity>(rider.lock()); xa = livingRider->xxa * .5f; ya = livingRider->yya;
// move much slower backwards if (ya <= 0) { ya *= .25f; gallopSoundCounter = 0; }
if (onGround && playerJumpPendingScale == 0 && isStanding() && !allowStandSliding) { xa = 0; ya = 0; }
if (playerJumpPendingScale > 0 && !getIsJumping() && onGround) { yd = getCustomJump() * playerJumpPendingScale; if (hasEffect(MobEffect::jump)) { yd += (getEffect(MobEffect::jump)->getAmplifier() + 1) * .1f; }
setIsJumping(true); hasImpulse = true;
if (ya > 0) { float sin = Mth::sin(yRot * PI / 180); float cos = Mth::cos(yRot * PI / 180);
xd += -0.4f * sin * playerJumpPendingScale; zd += 0.4f * cos * playerJumpPendingScale;
playSound(eSoundType_MOB_HORSE_JUMP, .4f, 1); } playerJumpPendingScale = 0; }
footSize = 1; flyingSpeed = getSpeed() * .1f; if (!level->isClientSide) { setSpeed((float) (getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue())); Animal::travel(xa, ya); }
if (onGround) { // blood - fixes jump bug playerJumpPendingScale = 0; setIsJumping(false); } walkAnimSpeedO = walkAnimSpeed; double dx = x - xo; double dz = z - zo; float wst = Mth::sqrt(dx * dx + dz * dz) * 4.0f; if (wst > 1.0f) { wst = 1.0f; }
walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; walkAnimPos += walkAnimSpeed;
}
void EntityHorse::addAdditonalSaveData(CompoundTag *tag){ Animal::addAdditonalSaveData(tag);
tag->putBoolean(L"EatingHaystack", isEating()); tag->putBoolean(L"ChestedHorse", isChestedHorse()); tag->putBoolean(L"HasReproduced", getHasReproduced()); tag->putBoolean(L"Bred", isBred()); tag->putInt(L"Type", getType()); tag->putInt(L"Variant", getVariant()); tag->putInt(L"Temper", getTemper()); tag->putBoolean(L"Tame", isTamed()); tag->putString(L"OwnerName", getOwnerName());
if (isChestedHorse()) { ListTag<CompoundTag> *listTag = new ListTag<CompoundTag>();
for (int i = INV_BASE_COUNT; i < inventory->getContainerSize(); i++) { shared_ptr<ItemInstance> stack = inventory->getItem(i);
if (stack != NULL) { CompoundTag *compoundTag = new CompoundTag();
compoundTag->putByte(L"Slot", (byte) i);
stack->save(compoundTag); listTag->add(compoundTag); } } tag->put(L"Items", listTag); }
if (inventory->getItem(INV_SLOT_ARMOR) != NULL) { tag->put(L"ArmorItem", inventory->getItem(INV_SLOT_ARMOR)->save(new CompoundTag(L"ArmorItem"))); } if (inventory->getItem(INV_SLOT_SADDLE) != NULL) { tag->put(L"SaddleItem", inventory->getItem(INV_SLOT_SADDLE)->save(new CompoundTag(L"SaddleItem"))); }}
void EntityHorse::readAdditionalSaveData(CompoundTag *tag){ Animal::readAdditionalSaveData(tag); setEating(tag->getBoolean(L"EatingHaystack")); setBred(tag->getBoolean(L"Bred")); setChestedHorse(tag->getBoolean(L"ChestedHorse")); setReproduced(tag->getBoolean(L"HasReproduced")); setType(tag->getInt(L"Type")); setVariant(tag->getInt(L"Variant")); setTemper(tag->getInt(L"Temper")); setTamed(tag->getBoolean(L"Tame")); if (tag->contains(L"OwnerName")) { setOwner(tag->getString(L"OwnerName")); }
// 4J: This is for handling old save data, not needed on console /*AttributeInstance *oldSpeedAttribute = getAttributes()->getInstance(SharedMonsterAttributes::MOVEMENT_SPEED);
if (oldSpeedAttribute != NULL) { getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(oldSpeedAttribute->getBaseValue() * 0.25f); }*/
if (isChestedHorse()) { ListTag<CompoundTag> *nbttaglist = (ListTag<CompoundTag> *) tag->getList(L"Items"); createInventory();
for (int i = 0; i < nbttaglist->size(); i++) { CompoundTag *compoundTag = nbttaglist->get(i); int slot = compoundTag->getByte(L"Slot") & 0xFF;
if (slot >= INV_BASE_COUNT && slot < inventory->getContainerSize()) { inventory->setItem(slot, ItemInstance::fromTag(compoundTag)); } } }
if (tag->contains(L"ArmorItem")) { shared_ptr<ItemInstance> armor = ItemInstance::fromTag(tag->getCompound(L"ArmorItem")); if (armor != NULL && isHorseArmor(armor->id)) { inventory->setItem(INV_SLOT_ARMOR, armor); } }
if (tag->contains(L"SaddleItem")) { shared_ptr<ItemInstance> saddleItem = ItemInstance::fromTag(tag->getCompound(L"SaddleItem")); if (saddleItem != NULL && saddleItem->id == Item::saddle_Id) { inventory->setItem(INV_SLOT_SADDLE, saddleItem); } } else if (tag->getBoolean(L"Saddle")) { inventory->setItem(INV_SLOT_SADDLE, shared_ptr<ItemInstance>( new ItemInstance(Item::saddle))); } updateEquipment();}
bool EntityHorse::canMate(shared_ptr<Animal> partner){ if (partner == shared_from_this()) return false; if (partner->GetType() != GetType()) return false;
shared_ptr<EntityHorse> horsePartner = dynamic_pointer_cast<EntityHorse>(partner);
if (!isReadyForParenting() || !horsePartner->isReadyForParenting()) { return false; } int type = getType(); int pType = horsePartner->getType();
return type == pType || (type == TYPE_HORSE && pType == TYPE_DONKEY) || (type == TYPE_DONKEY && pType == TYPE_HORSE);}
shared_ptr<AgableMob> EntityHorse::getBreedOffspring(shared_ptr<AgableMob> partner){ shared_ptr<EntityHorse> horsePartner = dynamic_pointer_cast<EntityHorse>(partner); shared_ptr<EntityHorse> baby = shared_ptr<EntityHorse>( new EntityHorse(level) );
int type = getType(); int partnerType = horsePartner->getType(); int babyType = TYPE_HORSE;
if (type == partnerType) { babyType = type; } else if (type == TYPE_HORSE && partnerType == TYPE_DONKEY || type == TYPE_DONKEY && partnerType == TYPE_HORSE) { babyType = TYPE_MULE; }
// select skin and marking colors if (babyType == TYPE_HORSE) { int skinResult; int selectSkin = random->nextInt(9); if (selectSkin < 4) { skinResult = getVariant() & 0xff; } else if (selectSkin < 8) { skinResult = horsePartner->getVariant() & 0xff; } else { skinResult = random->nextInt(VARIANTS); }
int selectMarking = random->nextInt(5); if (selectMarking < 4) { skinResult |= getVariant() & 0xff00; } else if (selectMarking < 8) { skinResult |= horsePartner->getVariant() & 0xff00; } else { skinResult |= (random->nextInt(MARKINGS) << 8) & 0xff00; } baby->setVariant(skinResult); }
baby->setType(babyType);
// generate stats from parents double maxHealth = getAttribute(SharedMonsterAttributes::MAX_HEALTH)->getBaseValue() + partner->getAttribute(SharedMonsterAttributes::MAX_HEALTH)->getBaseValue() + generateRandomMaxHealth(); baby->getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(maxHealth / 3.0f);
double jumpStrength = getAttribute(JUMP_STRENGTH)->getBaseValue() + partner->getAttribute(JUMP_STRENGTH)->getBaseValue() + generateRandomJumpStrength(); baby->getAttribute(JUMP_STRENGTH)->setBaseValue(jumpStrength / 3.0f);
double speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getBaseValue() + partner->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getBaseValue() + generateRandomSpeed(); baby->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(speed / 3.0f);
return baby;}
MobGroupData *EntityHorse::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param{ groupData = Animal::finalizeMobSpawn(groupData);
int type = 0; int variant = 0;
if ( dynamic_cast<HorseGroupData *>(groupData) != NULL ) { type = ((HorseGroupData *) groupData)->horseType; variant = ((HorseGroupData *) groupData)->horseVariant & 0xff | (random->nextInt(MARKINGS) << 8); } else { if(extraData != 0) { type = extraData - 1; } else if (random->nextInt(10) == 0) { type = TYPE_DONKEY; } else { type = TYPE_HORSE; }
if(type == TYPE_HORSE) { int skin = random->nextInt(VARIANTS); int mark = random->nextInt(MARKINGS); variant = skin | (mark << 8); } groupData = new HorseGroupData(type, variant); }
setType(type); setVariant(variant);
if (random->nextInt(5) == 0) { setAge(AgableMob::BABY_START_AGE); }
if (type == TYPE_SKELETON || type == TYPE_UNDEAD) { getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(15); getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); } else { getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(generateRandomMaxHealth()); if (type == TYPE_HORSE) { getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(generateRandomSpeed()); } else { getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.175f); } } if (type == TYPE_MULE || type == TYPE_DONKEY) { getAttribute(JUMP_STRENGTH)->setBaseValue(.5f); } else { getAttribute(JUMP_STRENGTH)->setBaseValue(generateRandomJumpStrength()); } setHealth(getMaxHealth());
return groupData;}
float EntityHorse::getEatAnim(float a){ return eatAnimO + (eatAnim - eatAnimO) * a;}
float EntityHorse::getStandAnim(float a){ return standAnimO + (standAnim - standAnimO) * a;}
float EntityHorse::getMouthAnim(float a){ return mouthAnimO + (mouthAnim - mouthAnimO) * a;}
bool EntityHorse::useNewAi(){ return true;}
void EntityHorse::onPlayerJump(int jumpAmount){ if (isSaddled()) { if (jumpAmount < 0) { jumpAmount = 0; } else { allowStandSliding = true; stand(); }
if (jumpAmount >= 90) { playerJumpPendingScale = 1.0f; } else { playerJumpPendingScale = .4f + .4f * (float) jumpAmount / 90.0f; } }}
void EntityHorse::spawnTamingParticles(bool success){ ePARTICLE_TYPE particle = success ? eParticleType_heart : eParticleType_smoke;
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(particle, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); }}
void EntityHorse::handleEntityEvent(byte id){ if (id == EntityEvent::TAMING_SUCCEEDED) { spawnTamingParticles(true); } else if (id == EntityEvent::TAMING_FAILED) { spawnTamingParticles(false); } else { Animal::handleEntityEvent(id); }}
void EntityHorse::positionRider(){ Animal::positionRider();
if (standAnimO > 0) { float sin = Mth::sin(yBodyRot * PI / 180); float cos = Mth::cos(yBodyRot * PI / 180); float dist = .7f * standAnimO; float height = .15f * standAnimO;
rider.lock()->setPos(x + dist * sin, y + getRideHeight() + rider.lock()->getRidingHeight() + height, z - dist * cos); if ( rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) { shared_ptr<LivingEntity> livingRider = dynamic_pointer_cast<LivingEntity>(rider.lock()); livingRider->yBodyRot = yBodyRot; } }}
// Health is between 15 and 30float EntityHorse::generateRandomMaxHealth(){ return 15.0f + random->nextInt(8) + random->nextInt(9);}
double EntityHorse::generateRandomJumpStrength(){ return .4f + random->nextDouble() * .2 + random->nextDouble() * .2 + random->nextDouble() * .2;}
double EntityHorse::generateRandomSpeed(){ double speed = (0.45f + random->nextDouble() * .3 + random->nextDouble() * .3 + random->nextDouble() * .3) * 0.25f; app.DebugPrintf("<EntityHorse::generateRandomSpeed> Speed: %f\n", speed); return speed;}
EntityHorse::HorseGroupData::HorseGroupData(int type, int variant){ horseType = type; horseVariant = variant;}
bool EntityHorse::isHorseArmor(int itemId){ return itemId == Item::horseArmorMetal_Id || itemId == Item::horseArmorGold_Id || itemId == Item::horseArmorDiamond_Id;}
bool EntityHorse::onLadder(){ // prevent horses from climbing ladders return false;}
shared_ptr<Player> EntityHorse::getOwner(){ return level->getPlayerByUUID(getOwnerName());}