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.
14 kB · 584 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584#include "stdafx.h"#include "net.minecraft.world.h"#include "net.minecraft.world.damagesource.h"#include "net.minecraft.world.entity.ai.attributes.h"#include "net.minecraft.world.entity.ai.goal.h"#include "net.minecraft.world.entity.ai.goal.target.h"#include "net.minecraft.world.entity.ai.navigation.h"#include "net.minecraft.world.entity.monster.h"#include "net.minecraft.world.entity.projectile.h"#include "net.minecraft.world.entity.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.level.h"#include "net.minecraft.world.level.tile.h"#include "net.minecraft.world.phys.h"#include "Mth.h"
#include "SoundTypes.h"
#include "WitherBoss.h"
bool LivingEntitySelector::matches(shared_ptr<Entity> entity) const{ if ( entity->instanceof(eTYPE_LIVINGENTITY) ) { return dynamic_pointer_cast<LivingEntity>(entity)->getMobType() != UNDEAD; } else { return false; }}
EntitySelector *WitherBoss::livingEntitySelector = new LivingEntitySelector();
WitherBoss::WitherBoss(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(); setHealth(getMaxHealth());
for(unsigned int i = 0; i < 2; ++i) { xRotHeads[i] = 0.0f; yRotHeads[i] = 0.0f; xRotOHeads[i] = 0.0f; yRotOHeads[i] = 0.0f; nextHeadUpdate[i] = 0; idleHeadUpdates[i] = 0; } destroyBlocksTick = 0;
setSize(.9f, 4);
// noPhysics = true; fireImmune = true;
// noCulling = true;
getNavigation()->setCanFloat(true);
goalSelector.addGoal(0, new FloatGoal(this)); goalSelector.addGoal(2, new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 2, 20));
goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(7, new RandomLookAroundGoal(this));
targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Mob), 0, false, false, livingEntitySelector));
xpReward = Enemy::XP_REWARD_BOSS;}
void WitherBoss::defineSynchedData(){ Monster::defineSynchedData();
entityData->define(DATA_TARGET_A, (int)0); entityData->define(DATA_TARGET_B, (int)0); entityData->define(DATA_TARGET_C, (int)0); entityData->define(DATA_ID_INV, (int)0);}
void WitherBoss::addAdditonalSaveData(CompoundTag *entityTag){ Monster::addAdditonalSaveData(entityTag);
entityTag->putInt(L"Invul", getInvulnerableTicks());}
void WitherBoss::readAdditionalSaveData(CompoundTag *tag){ Monster::readAdditionalSaveData(tag);
setInvulnerableTicks(tag->getInt(L"Invul"));}
float WitherBoss::getShadowHeightOffs(){ return bbHeight / 8;}
int WitherBoss::getAmbientSound(){ return eSoundType_MOB_WITHER_IDLE; //"mob.wither.idle";}
int WitherBoss::getHurtSound(){ return eSoundType_MOB_WITHER_HURT; //"mob.wither.hurt";}
int WitherBoss::getDeathSound(){ return eSoundType_MOB_WITHER_DEATH; //"mob.wither.death";}
void WitherBoss::aiStep(){ yd *= 0.6f;
if (!level->isClientSide && getAlternativeTarget(0) > 0) { shared_ptr<Entity> e = level->getEntity(getAlternativeTarget(0)); if (e != NULL) { if ((y < e->y) || (!isPowered() && y < (e->y + 5))) { if (yd < 0) { yd = 0; } yd += (.5f - yd) * .6f; }
double xdist = e->x - x; double zdist = e->z - z; double distSqr = xdist * xdist + zdist * zdist; if (distSqr > 9) { double sd = Mth::sqrt(distSqr); xd += ((xdist / sd) * .5f - xd) * .6f; zd += ((zdist / sd) * .5f - zd) * .6f; } } } if ((xd * xd + zd * zd) > .05f) { yRot = (float) atan2(zd, xd) * Mth::RADDEG - 90; } Monster::aiStep();
for (int i = 0; i < 2; i++) { yRotOHeads[i] = yRotHeads[i]; xRotOHeads[i] = xRotHeads[i]; }
for (int i = 0; i < 2; i++) { int entityId = getAlternativeTarget(i + 1); shared_ptr<Entity> e = nullptr; if (entityId > 0) { e = level->getEntity(entityId); } if (e != NULL) { double hx = getHeadX(i + 1); double hy = getHeadY(i + 1); double hz = getHeadZ(i + 1);
double xd = e->x - hx; double yd = e->y + e->getHeadHeight() - hy; double zd = e->z - hz; 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); xRotHeads[i] = rotlerp(xRotHeads[i], xRotD, 40); yRotHeads[i] = rotlerp(yRotHeads[i], yRotD, 10);
} else { yRotHeads[i] = rotlerp(yRotHeads[i], yBodyRot, 10); } } bool _isPowered = isPowered(); for (int i = 0; i < 3; i++) { double hx = getHeadX(i); double hy = getHeadY(i); double hz = getHeadZ(i);
level->addParticle(eParticleType_smoke, hx + random->nextGaussian() * .3f, hy + random->nextGaussian() * .3f, hz + random->nextGaussian() * .3f, 0, 0, 0); if (_isPowered && level->random->nextInt(4) == 0) { level->addParticle(eParticleType_mobSpell, hx + random->nextGaussian() * .3f, hy + random->nextGaussian() * .3f, hz + random->nextGaussian() * .3f, .7f, .7f, .5f); } } if (getInvulnerableTicks() > 0) { for (int i = 0; i < 3; i++) { level->addParticle(eParticleType_mobSpell, x + random->nextGaussian() * 1.0f, y + random->nextFloat() * 3.3f, z + random->nextGaussian() * 1.0f, .7f, .7f, .9f); } }}
void WitherBoss::newServerAiStep(){ if (getInvulnerableTicks() > 0) { int newCount = getInvulnerableTicks() - 1;
if (newCount <= 0) { level->explode(shared_from_this(), x, y + getHeadHeight(), z, 7, false, level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)); level->globalLevelEvent(LevelEvent::SOUND_WITHER_BOSS_SPAWN, (int) x, (int) y, (int) z, 0); }
setInvulnerableTicks(newCount); if (tickCount % 10 == 0) { heal(10); }
return; }
Monster::newServerAiStep();
for (int i = 1; i < 3; i++) { if (tickCount >= nextHeadUpdate[i - 1]) { nextHeadUpdate[i - 1] = tickCount + SharedConstants::TICKS_PER_SECOND / 2 + random->nextInt(SharedConstants::TICKS_PER_SECOND / 2);
if (level->difficulty >= Difficulty::NORMAL && idleHeadUpdates[i - 1]++ > 15) { float hrange = 10; float vrange = 5; double xt = Mth::nextDouble(random, x - hrange, x + hrange); double yt = Mth::nextDouble(random, y - vrange, y + vrange); double zt = Mth::nextDouble(random, z - hrange, z + hrange); performRangedAttack(i + 1, xt, yt, zt, true); idleHeadUpdates[i - 1] = 0; }
int headTarget = getAlternativeTarget(i); if (headTarget > 0) { shared_ptr<Entity> current = level->getEntity(headTarget);
// 4J: Added check for instance of living entity, had a problem with IDs being recycled to other entities if (current == NULL || !current->instanceof(eTYPE_LIVINGENTITY) || !current->isAlive() || distanceToSqr(current) > 30 * 30 || !canSee(current)) { setAlternativeTarget(i, 0); } else { performRangedAttack(i + 1, dynamic_pointer_cast<LivingEntity>(current) ); nextHeadUpdate[i - 1] = tickCount + SharedConstants::TICKS_PER_SECOND * 2 + random->nextInt(SharedConstants::TICKS_PER_SECOND); idleHeadUpdates[i - 1] = 0; } } else { vector<shared_ptr<Entity> > *entities = level->getEntitiesOfClass(typeid(LivingEntity), bb->grow(20, 8, 20), livingEntitySelector); // randomly try to find a target 10 times for (int attempt = 0; attempt < 10 && !entities->empty(); attempt++) { int randomIndex = random->nextInt(entities->size()); shared_ptr<LivingEntity> selected = dynamic_pointer_cast<LivingEntity>( entities->at(randomIndex) );
if (selected != shared_from_this() && selected->isAlive() && canSee(selected)) { if ( selected->instanceof(eTYPE_PLAYER) ) { if (!dynamic_pointer_cast<Player>(selected)->abilities.invulnerable) { assert(selected->instanceof(eTYPE_LIVINGENTITY)); setAlternativeTarget(i, selected->entityId); } break; } else { assert(selected->instanceof(eTYPE_LIVINGENTITY)); setAlternativeTarget(i, selected->entityId); break; } } // don't pick this again entities->erase(entities->begin() + randomIndex); } delete entities; } } } if (getTarget() != NULL) { assert(getTarget()->instanceof(eTYPE_LIVINGENTITY)); setAlternativeTarget(0, getTarget()->entityId); } else { setAlternativeTarget(0, 0); }
if (destroyBlocksTick > 0) { destroyBlocksTick--;
if (destroyBlocksTick == 0 && level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) { // destroy all blocks that are within 1 range, counting from // feet and 3 blocks up
int feet = Mth::floor(y); int ox = Mth::floor(x); int oz = Mth::floor(z); bool destroyed = false;
for (int xStep = -1; xStep <= 1; xStep++) { for (int zStep = -1; zStep <= 1; zStep++) { for (int yStep = 0; yStep <= 3; yStep++) { int tx = ox + xStep; int ty = feet + yStep; int tz = oz + zStep; int tile = level->getTile(tx, ty, tz); if (tile > 0 && tile != Tile::unbreakable_Id && tile != Tile::endPortalTile_Id && tile != Tile::endPortalFrameTile_Id) { destroyed = level->destroyTile(tx, ty, tz, true) || destroyed; } } } } if (destroyed) { level->levelEvent(nullptr, LevelEvent::SOUND_ZOMBIE_DOOR_CRASH, (int) x, (int) y, (int) z, 0); } } }
if ((tickCount % (SharedConstants::TICKS_PER_SECOND)) == 0) { heal(1); }}
void WitherBoss::makeInvulnerable(){ setInvulnerableTicks(SharedConstants::TICKS_PER_SECOND * 11); setHealth(getMaxHealth() / 3);}
void WitherBoss::makeStuckInWeb(){}
int WitherBoss::getArmorValue(){ return 4;}
double WitherBoss::getHeadX(int index){ if (index <= 0) { return x; } float headAngle = (yBodyRot + 180 * (index - 1)) / 180.0f * PI; float cos = Mth::cos(headAngle); return x + cos * 1.3;}
double WitherBoss::getHeadY(int index){ if (index <= 0) { return y + 3; } else { return y + 2.2; }}
double WitherBoss::getHeadZ(int index){ if (index <= 0) { return z; } float headAngle = (yBodyRot + 180 * (index - 1)) / 180.0f * PI; float sin = Mth::sin(headAngle); return z + sin * 1.3;}
float WitherBoss::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;}
void WitherBoss::performRangedAttack(int head, shared_ptr<LivingEntity> target){ performRangedAttack(head, target->x, target->y + target->getHeadHeight() * .5, target->z, head == 0 && random->nextFloat() < 0.001f);}
void WitherBoss::performRangedAttack(int head, double tx, double ty, double tz, bool dangerous){ level->levelEvent(nullptr, LevelEvent::SOUND_WITHER_BOSS_SHOOT, (int) x, (int) y, (int) z, 0);
double hx = getHeadX(head); double hy = getHeadY(head); double hz = getHeadZ(head);
double xd = tx - hx; double yd = ty - hy; double zd = tz - hz;
shared_ptr<WitherSkull> ie = shared_ptr<WitherSkull>( new WitherSkull(level, dynamic_pointer_cast<LivingEntity>(shared_from_this()), xd, yd, zd) ); if (dangerous) ie->setDangerous(true); ie->y = hy; ie->x = hx; ie->z = hz; level->addEntity(ie);}
void WitherBoss::performRangedAttack(shared_ptr<LivingEntity> target, float power){ performRangedAttack(0, target);}
bool WitherBoss::hurt(DamageSource *source, float dmg){ if (isInvulnerable()) return false; if (source == DamageSource::drown) return false; if (getInvulnerableTicks() > 0) { return false; }
if (isPowered()) { shared_ptr<Entity> directEntity = source->getDirectEntity(); if (directEntity != NULL && directEntity->GetType() == eTYPE_ARROW) { return false; } }
shared_ptr<Entity> sourceEntity = source->getEntity(); if (sourceEntity != NULL) { if ( sourceEntity->instanceof(eTYPE_PLAYER) ) { } else if ( sourceEntity->instanceof(eTYPE_LIVINGENTITY) && dynamic_pointer_cast<LivingEntity>(sourceEntity)->getMobType() == getMobType()) { // can't be harmed by other undead return false; } } if (destroyBlocksTick <= 0) { destroyBlocksTick = SharedConstants::TICKS_PER_SECOND; }
for (int i = 0; i < IDLE_HEAD_UPDATES_SIZE; i++) { idleHeadUpdates[i] += 3; }
return Monster::hurt(source, dmg);}
void WitherBoss::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel){ spawnAtLocation(Item::netherStar_Id, 1);}
void WitherBoss::checkDespawn(){ noActionTime = 0;}
int WitherBoss::getLightColor(float a){ return SharedConstants::FULLBRIGHT_LIGHTVALUE;}
bool WitherBoss::isPickable(){ return !removed;}
void WitherBoss::causeFallDamage(float distance){}
void WitherBoss::addEffect(MobEffectInstance *newEffect){ // do nothing}
bool WitherBoss::useNewAi(){ return true;}
void WitherBoss::registerAttributes(){ Monster::registerAttributes();
getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(300); getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.6f);
// 4J Stu - Don't make it so far! //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40);}
float WitherBoss::getHeadYRot(int i){ return yRotHeads[i];}
float WitherBoss::getHeadXRot(int i){ return xRotHeads[i];}
int WitherBoss::getInvulnerableTicks(){ return entityData->getInteger(DATA_ID_INV);}
void WitherBoss::setInvulnerableTicks(int invulnerableTicks){ entityData->set(DATA_ID_INV, invulnerableTicks);}
int WitherBoss::getAlternativeTarget(int headIndex){ return entityData->getInteger(DATA_TARGET_A + headIndex);}
void WitherBoss::setAlternativeTarget(int headIndex, int entityId){ entityData->set(DATA_TARGET_A + headIndex, entityId);}
bool WitherBoss::isPowered(){ return getHealth() <= getMaxHealth() / 2;}
MobType WitherBoss::getMobType(){ return UNDEAD;}
void WitherBoss::ride(shared_ptr<Entity> e){ riding = nullptr;}