diff options
Diffstat (limited to 'Minecraft.World/Skeleton.cpp')
| -rw-r--r-- | Minecraft.World/Skeleton.cpp | 309 |
1 files changed, 257 insertions, 52 deletions
diff --git a/Minecraft.World/Skeleton.cpp b/Minecraft.World/Skeleton.cpp index b6dbab1f..9afb95c6 100644 --- a/Minecraft.World/Skeleton.cpp +++ b/Minecraft.World/Skeleton.cpp @@ -1,14 +1,20 @@ #include "stdafx.h" #include "net.minecraft.world.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.dimension.h" +#include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.entity.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.projectile.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.stats.h" #include "net.minecraft.world.damagesource.h" #include "SharedConstants.h" @@ -16,63 +22,86 @@ #include "..\Minecraft.Client\Textures.h" #include "SoundTypes.h" - - Skeleton::Skeleton(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()); - // 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_SKELETON; // 4J was L"/mob/skeleton.png"; - - runSpeed = 0.25f; + bowGoal = new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 1, SharedConstants::TICKS_PER_SECOND * 3, 15); + meleeGoal = new MeleeAttackGoal(this, eTYPE_PLAYER, 1.2, false); goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(2, new RestrictSunGoal(this)); - goalSelector.addGoal(3, new FleeSunGoal(this, runSpeed)); - goalSelector.addGoal(4, new ArrowAttackGoal(this, runSpeed, ArrowAttackGoal::ArrowType, SharedConstants::TICKS_PER_SECOND * 3)); - goalSelector.addGoal(5, new RandomStrollGoal(this, runSpeed)); + goalSelector.addGoal(3, new FleeSunGoal(this, 1.0)); + goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(6, new RandomLookAroundGoal(this)); targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); - targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 16, 0, true)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true)); + + if (level != NULL && !level->isClientSide) reassessWeaponGoal(); } -bool Skeleton::useNewAi() +Skeleton::~Skeleton() { - return true; + delete bowGoal; + delete meleeGoal; +} + +void Skeleton::registerAttributes() +{ + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); +} + +void Skeleton::defineSynchedData() +{ + Monster::defineSynchedData(); + + entityData->define(DATA_TYPE_ID, (byte) TYPE_DEFAULT); } -int Skeleton::getMaxHealth() +bool Skeleton::useNewAi() { - return 20; + return true; } int Skeleton::getAmbientSound() { - return eSoundType_MOB_SKELETON_AMBIENT; + return eSoundType_MOB_SKELETON_AMBIENT; } int Skeleton::getHurtSound() { - return eSoundType_MOB_SKELETON_HURT; + return eSoundType_MOB_SKELETON_HURT; } int Skeleton::getDeathSound() { - return eSoundType_MOB_SKELETON_HURT; + return eSoundType_MOB_SKELETON_DEATH; } -shared_ptr<ItemInstance> Skeleton::bow; +void Skeleton::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_SKELETON_STEP, 0.15f, 1); +} -shared_ptr<ItemInstance> Skeleton::getCarriedItem() +bool Skeleton::doHurtTarget(shared_ptr<Entity> target) { - return bow; + if (Monster::doHurtTarget(target)) + { + if ( (getSkeletonType() == TYPE_WITHER) && target->instanceof(eTYPE_LIVINGENTITY) ) + { + dynamic_pointer_cast<LivingEntity>(target)->addEffect(new MobEffectInstance(MobEffect::wither->id, SharedConstants::TICKS_PER_SECOND * 10)); + } + return true; + } + return false; } MobType Skeleton::getMobType() @@ -82,28 +111,65 @@ MobType Skeleton::getMobType() void Skeleton::aiStep() { - // isClientSide check brought forward from 1.8 (I assume it's related to the lighting changes) - if (level->isDay() && !level->isClientSide) + if (level->isDay() && !level->isClientSide) { - float br = getBrightness(1); - if (br > 0.5f) + float br = getBrightness(1); + if (br > 0.5f && random->nextFloat() * 30 < (br - 0.4f) * 2 && level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z))) { - if (level->canSeeSky( Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2) + bool burn = true; + + shared_ptr<ItemInstance> helmet = getCarried(SLOT_HELM); + if (helmet != NULL) { - setOnFire(8); - } - } - } + if (helmet->isDamageableItem()) + { + helmet->setAuxValue(helmet->getDamageValue() + random->nextInt(2)); + if (helmet->getDamageValue() >= helmet->getMaxDamage()) + { + breakItem(helmet); + setEquippedSlot(SLOT_HELM, nullptr); + } + } + + burn = false; + } + + if (burn) + { + setOnFire(8); + } + } + } + if (level->isClientSide) + { + if (getSkeletonType() == TYPE_WITHER) + { + setSize(0.6f * 1.2f, 1.8f * 1.3f); + } + } + + Monster::aiStep(); +} + +void Skeleton::rideTick() +{ + Monster::rideTick(); + + if ( riding != NULL && riding->instanceof(eTYPE_PATHFINDER_MOB) ) + { + yBodyRot = dynamic_pointer_cast<PathfinderMob>(riding)->yBodyRot; + } - Monster::aiStep(); } void Skeleton::die(DamageSource *source) { Monster::die(source); - shared_ptr<Player> player = dynamic_pointer_cast<Player>( source->getEntity() ); - if ( 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) ) { + shared_ptr<Player> player = dynamic_pointer_cast<Player>( source->getEntity() ); + double xd = player->x - x; double zd = player->z - z; if (xd * xd + zd * zd >= 50 * 50) @@ -115,40 +181,179 @@ void Skeleton::die(DamageSource *source) int Skeleton::getDeathLoot() { - return Item::arrow->id; + return Item::arrow->id; } void Skeleton::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) { - // drop some arrows - int count = random->nextInt(3 + playerBonusLevel); - for (int i = 0; i < count; i++) + if (getSkeletonType() == TYPE_WITHER) { - spawnAtLocation(Item::arrow->id, 1); - } - // and some bones - count = random->nextInt(3 + playerBonusLevel); - for (int i = 0; i < count; i++) + // drop some arrows + int count = random->nextInt(3 + playerBonusLevel) - 1; + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::coal_Id, 1); + } + } + else { - spawnAtLocation(Item::bone->id, 1); - } + // drop some arrows + int count = random->nextInt(3 + playerBonusLevel); + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::arrow_Id, 1); + } + } + + // and some bones + int count = random->nextInt(3 + playerBonusLevel); + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::bone->id, 1); + } } void Skeleton::dropRareDeathLoot(int rareLootLevel) { - if (rareLootLevel > 0) + if (getSkeletonType() == TYPE_WITHER) + { + spawnAtLocation( shared_ptr<ItemInstance>( new ItemInstance(Item::skull_Id, 1, SkullTileEntity::TYPE_WITHER) ), 0); + } +} + +void Skeleton::populateDefaultEquipmentSlots() +{ + Monster::populateDefaultEquipmentSlots(); + + setEquippedSlot(SLOT_WEAPON, shared_ptr<ItemInstance>( new ItemInstance(Item::bow))); +} + +MobGroupData *Skeleton::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param +{ + groupData = Monster::finalizeMobSpawn(groupData); + + if ( dynamic_cast<HellDimension *>(level->dimension) != NULL && getRandom()->nextInt(5) > 0) + { + goalSelector.addGoal(4, meleeGoal, false); + + setSkeletonType(TYPE_WITHER); + setEquippedSlot(SLOT_WEAPON, shared_ptr<ItemInstance>( new ItemInstance(Item::sword_stone))); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(4); + } + else + { + goalSelector.addGoal(4, bowGoal, false); + + populateDefaultEquipmentSlots(); + populateDefaultEquipmentEnchantments(); + } + + setCanPickUpLoot(random->nextFloat() < MAX_PICKUP_LOOT_CHANCE * level->getDifficulty(x, y, z)); + + if (getCarried(SLOT_HELM) == NULL) + { + if (Calendar::GetMonth() + 1 == 10 && Calendar::GetDayOfMonth() == 31 && random->nextFloat() < 0.25f) + { + // Halloween! OooOOo! 25% of all skeletons/zombies can wear pumpkins on their heads. + setEquippedSlot(SLOT_HELM, shared_ptr<ItemInstance>( new ItemInstance(random->nextFloat() < 0.1f ? Tile::litPumpkin : Tile::pumpkin))); + dropChances[SLOT_HELM] = 0; + } + } + return groupData; +} + +void Skeleton::reassessWeaponGoal() +{ + goalSelector.removeGoal(meleeGoal); + goalSelector.removeGoal(bowGoal); + + shared_ptr<ItemInstance> carried = getCarriedItem(); + + if (carried != NULL && carried->id == Item::bow_Id) { - shared_ptr<ItemInstance> bow = shared_ptr<ItemInstance>( new ItemInstance(Item::bow) ); - EnchantmentHelper::enchantItem(random, bow, 5); - spawnAtLocation(bow, 0); + goalSelector.addGoal(4, bowGoal, false); } else { - spawnAtLocation(Item::bow_Id, 1); + goalSelector.addGoal(4, meleeGoal, false); } } -void Skeleton::staticCtor() +void Skeleton::performRangedAttack(shared_ptr<LivingEntity> target, float power) { - Skeleton::bow = shared_ptr<ItemInstance>( new ItemInstance(Item::bow, 1) ); + shared_ptr<Arrow> arrow = shared_ptr<Arrow>( new Arrow(level, dynamic_pointer_cast<LivingEntity>(shared_from_this()), target, 1.60f, 14 - (level->difficulty * 4)) ); + int damageBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowBonus->id, getCarriedItem()); + int knockbackBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowKnockback->id, getCarriedItem()); + + arrow->setBaseDamage(power * 2.0f + (random->nextGaussian() * 0.25f + (level->difficulty * 0.11f))); + + if (damageBonus > 0) + { + arrow->setBaseDamage(arrow->getBaseDamage() + (double) damageBonus * .5 + .5); + } + if (knockbackBonus > 0) + { + arrow->setKnockback(knockbackBonus); + } + if (EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowFire->id, getCarriedItem()) > 0 || getSkeletonType() == TYPE_WITHER) + { + arrow->setOnFire(100); + } + + playSound(eSoundType_RANDOM_BOW, 1.0f, 1 / (getRandom()->nextFloat() * 0.4f + 0.8f)); + level->addEntity(arrow); } + +int Skeleton::getSkeletonType() +{ + return (int) entityData->getByte(DATA_TYPE_ID); +} + +void Skeleton::setSkeletonType(int type) +{ + entityData->set(DATA_TYPE_ID, (byte) type); + + fireImmune = type == TYPE_WITHER; + if (type == TYPE_WITHER) + { + setSize(0.6f * 1.2f, 1.8f * 1.3f); + } + else + { + setSize(0.6f, 1.8f); + } +} + +void Skeleton::readAdditionalSaveData(CompoundTag *tag) +{ + Monster::readAdditionalSaveData(tag); + + if (tag->contains(L"SkeletonType")) + { + int value = tag->getByte(L"SkeletonType"); + setSkeletonType(value); + } + + reassessWeaponGoal(); +} + +void Skeleton::addAdditonalSaveData(CompoundTag *entityTag) +{ + Monster::addAdditonalSaveData(entityTag); + entityTag->putByte(L"SkeletonType", (byte) getSkeletonType()); +} + +void Skeleton::setEquippedSlot(int slot, shared_ptr<ItemInstance> item) +{ + Monster::setEquippedSlot(slot, item); + + if (!level->isClientSide && slot == SLOT_WEAPON) + { + reassessWeaponGoal(); + } +} + +double Skeleton::getRidingHeight() +{ + return Monster::getRidingHeight() - .5; +}
\ No newline at end of file |
