the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "net.minecraft.world.h"
3#include "net.minecraft.world.level.h"
4#include "net.minecraft.world.level.dimension.h"
5#include "net.minecraft.world.level.tile.entity.h"
6#include "net.minecraft.world.item.h"
7#include "net.minecraft.world.item.enchantment.h"
8#include "net.minecraft.world.effect.h"
9#include "net.minecraft.world.entity.h"
10#include "net.minecraft.world.entity.ai.attributes.h"
11#include "net.minecraft.world.entity.ai.goal.h"
12#include "net.minecraft.world.entity.ai.goal.target.h"
13#include "net.minecraft.world.entity.ai.navigation.h"
14#include "net.minecraft.world.entity.projectile.h"
15#include "net.minecraft.world.entity.item.h"
16#include "net.minecraft.world.entity.player.h"
17#include "net.minecraft.world.entity.monster.h"
18#include "net.minecraft.stats.h"
19#include "net.minecraft.world.damagesource.h"
20#include "SharedConstants.h"
21#include "Skeleton.h"
22#include "..\Minecraft.Client\Textures.h"
23#include "SoundTypes.h"
24
25Skeleton::Skeleton(Level *level) : Monster( level )
26{
27 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
28 // the derived version of the function is called
29 this->defineSynchedData();
30 registerAttributes();
31 setHealth(getMaxHealth());
32
33 bowGoal = new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 1, SharedConstants::TICKS_PER_SECOND * 3, 15);
34 meleeGoal = new MeleeAttackGoal(this, eTYPE_PLAYER, 1.2, false);
35
36 goalSelector.addGoal(1, new FloatGoal(this));
37 goalSelector.addGoal(2, new RestrictSunGoal(this));
38 goalSelector.addGoal(3, new FleeSunGoal(this, 1.0));
39 goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0));
40 goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8));
41 goalSelector.addGoal(6, new RandomLookAroundGoal(this));
42
43 targetSelector.addGoal(1, new HurtByTargetGoal(this, false));
44 targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true));
45
46 if (level != NULL && !level->isClientSide) reassessWeaponGoal();
47}
48
49Skeleton::~Skeleton()
50{
51 delete bowGoal;
52 delete meleeGoal;
53}
54
55void Skeleton::registerAttributes()
56{
57 Monster::registerAttributes();
58
59 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f);
60}
61
62void Skeleton::defineSynchedData()
63{
64 Monster::defineSynchedData();
65
66 entityData->define(DATA_TYPE_ID, (byte) TYPE_DEFAULT);
67}
68
69bool Skeleton::useNewAi()
70{
71 return true;
72}
73
74int Skeleton::getAmbientSound()
75{
76 return eSoundType_MOB_SKELETON_AMBIENT;
77}
78
79int Skeleton::getHurtSound()
80{
81 return eSoundType_MOB_SKELETON_HURT;
82}
83
84int Skeleton::getDeathSound()
85{
86 return eSoundType_MOB_SKELETON_DEATH;
87}
88
89void Skeleton::playStepSound(int xt, int yt, int zt, int t)
90{
91 playSound(eSoundType_MOB_SKELETON_STEP, 0.15f, 1);
92}
93
94bool Skeleton::doHurtTarget(shared_ptr<Entity> target)
95{
96 if (Monster::doHurtTarget(target))
97 {
98 if ( (getSkeletonType() == TYPE_WITHER) && target->instanceof(eTYPE_LIVINGENTITY) )
99 {
100 dynamic_pointer_cast<LivingEntity>(target)->addEffect(new MobEffectInstance(MobEffect::wither->id, SharedConstants::TICKS_PER_SECOND * 10));
101 }
102 return true;
103 }
104 return false;
105}
106
107MobType Skeleton::getMobType()
108{
109 return UNDEAD;
110}
111
112void Skeleton::aiStep()
113{
114 if (level->isDay() && !level->isClientSide)
115 {
116 float br = getBrightness(1);
117 if (br > 0.5f && random->nextFloat() * 30 < (br - 0.4f) * 2 && level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z)))
118 {
119 bool burn = true;
120
121 shared_ptr<ItemInstance> helmet = getCarried(SLOT_HELM);
122 if (helmet != NULL)
123 {
124 if (helmet->isDamageableItem())
125 {
126 helmet->setAuxValue(helmet->getDamageValue() + random->nextInt(2));
127 if (helmet->getDamageValue() >= helmet->getMaxDamage())
128 {
129 breakItem(helmet);
130 setEquippedSlot(SLOT_HELM, nullptr);
131 }
132 }
133
134 burn = false;
135 }
136
137 if (burn)
138 {
139 setOnFire(8);
140 }
141 }
142 }
143 if (level->isClientSide)
144 {
145 if (getSkeletonType() == TYPE_WITHER)
146 {
147 setSize(0.6f * 1.2f, 1.8f * 1.3f);
148 }
149 }
150
151 Monster::aiStep();
152}
153
154void Skeleton::rideTick()
155{
156 Monster::rideTick();
157
158 if ( riding != NULL && riding->instanceof(eTYPE_PATHFINDER_MOB) )
159 {
160 yBodyRot = dynamic_pointer_cast<PathfinderMob>(riding)->yBodyRot;
161 }
162
163}
164
165void Skeleton::die(DamageSource *source)
166{
167 Monster::die(source);
168
169 if ( source->getDirectEntity() != NULL && source->getDirectEntity()->instanceof(eTYPE_ARROW) && source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) )
170 {
171 shared_ptr<Player> player = dynamic_pointer_cast<Player>( source->getEntity() );
172
173 double xd = player->x - x;
174 double zd = player->z - z;
175 if (xd * xd + zd * zd >= 50 * 50)
176 {
177 player->awardStat(GenericStats::snipeSkeleton(), GenericStats::param_snipeSkeleton());
178 }
179 }
180}
181
182int Skeleton::getDeathLoot()
183{
184 return Item::arrow->id;
185}
186
187void Skeleton::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
188{
189 if (getSkeletonType() == TYPE_WITHER)
190 {
191 // drop some arrows
192 int count = random->nextInt(3 + playerBonusLevel) - 1;
193 for (int i = 0; i < count; i++)
194 {
195 spawnAtLocation(Item::coal_Id, 1);
196 }
197 }
198 else
199 {
200 // drop some arrows
201 int count = random->nextInt(3 + playerBonusLevel);
202 for (int i = 0; i < count; i++)
203 {
204 spawnAtLocation(Item::arrow_Id, 1);
205 }
206 }
207
208 // and some bones
209 int count = random->nextInt(3 + playerBonusLevel);
210 for (int i = 0; i < count; i++)
211 {
212 spawnAtLocation(Item::bone->id, 1);
213 }
214}
215
216void Skeleton::dropRareDeathLoot(int rareLootLevel)
217{
218 if (getSkeletonType() == TYPE_WITHER)
219 {
220 spawnAtLocation( shared_ptr<ItemInstance>( new ItemInstance(Item::skull_Id, 1, SkullTileEntity::TYPE_WITHER) ), 0);
221 }
222}
223
224void Skeleton::populateDefaultEquipmentSlots()
225{
226 Monster::populateDefaultEquipmentSlots();
227
228 setEquippedSlot(SLOT_WEAPON, shared_ptr<ItemInstance>( new ItemInstance(Item::bow)));
229}
230
231MobGroupData *Skeleton::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param
232{
233 groupData = Monster::finalizeMobSpawn(groupData);
234
235 if ( dynamic_cast<HellDimension *>(level->dimension) != NULL && getRandom()->nextInt(5) > 0)
236 {
237 goalSelector.addGoal(4, meleeGoal, false);
238
239 setSkeletonType(TYPE_WITHER);
240 setEquippedSlot(SLOT_WEAPON, shared_ptr<ItemInstance>( new ItemInstance(Item::sword_stone)));
241 getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(4);
242 }
243 else
244 {
245 goalSelector.addGoal(4, bowGoal, false);
246
247 populateDefaultEquipmentSlots();
248 populateDefaultEquipmentEnchantments();
249 }
250
251 setCanPickUpLoot(random->nextFloat() < MAX_PICKUP_LOOT_CHANCE * level->getDifficulty(x, y, z));
252
253 if (getCarried(SLOT_HELM) == NULL)
254 {
255 if (Calendar::GetMonth() + 1 == 10 && Calendar::GetDayOfMonth() == 31 && random->nextFloat() < 0.25f)
256 {
257 // Halloween! OooOOo! 25% of all skeletons/zombies can wear pumpkins on their heads.
258 setEquippedSlot(SLOT_HELM, shared_ptr<ItemInstance>( new ItemInstance(random->nextFloat() < 0.1f ? Tile::litPumpkin : Tile::pumpkin)));
259 dropChances[SLOT_HELM] = 0;
260 }
261 }
262 return groupData;
263}
264
265void Skeleton::reassessWeaponGoal()
266{
267 goalSelector.removeGoal(meleeGoal);
268 goalSelector.removeGoal(bowGoal);
269
270 shared_ptr<ItemInstance> carried = getCarriedItem();
271
272 if (carried != NULL && carried->id == Item::bow_Id)
273 {
274 goalSelector.addGoal(4, bowGoal, false);
275 }
276 else
277 {
278 goalSelector.addGoal(4, meleeGoal, false);
279 }
280}
281
282void Skeleton::performRangedAttack(shared_ptr<LivingEntity> target, float power)
283{
284 shared_ptr<Arrow> arrow = shared_ptr<Arrow>( new Arrow(level, dynamic_pointer_cast<LivingEntity>(shared_from_this()), target, 1.60f, 14 - (level->difficulty * 4)) );
285 int damageBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowBonus->id, getCarriedItem());
286 int knockbackBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowKnockback->id, getCarriedItem());
287
288 arrow->setBaseDamage(power * 2.0f + (random->nextGaussian() * 0.25f + (level->difficulty * 0.11f)));
289
290 if (damageBonus > 0)
291 {
292 arrow->setBaseDamage(arrow->getBaseDamage() + (double) damageBonus * .5 + .5);
293 }
294 if (knockbackBonus > 0)
295 {
296 arrow->setKnockback(knockbackBonus);
297 }
298 if (EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowFire->id, getCarriedItem()) > 0 || getSkeletonType() == TYPE_WITHER)
299 {
300 arrow->setOnFire(100);
301 }
302
303 playSound(eSoundType_RANDOM_BOW, 1.0f, 1 / (getRandom()->nextFloat() * 0.4f + 0.8f));
304 level->addEntity(arrow);
305}
306
307int Skeleton::getSkeletonType()
308{
309 return (int) entityData->getByte(DATA_TYPE_ID);
310}
311
312void Skeleton::setSkeletonType(int type)
313{
314 entityData->set(DATA_TYPE_ID, (byte) type);
315
316 fireImmune = type == TYPE_WITHER;
317 if (type == TYPE_WITHER)
318 {
319 setSize(0.6f * 1.2f, 1.8f * 1.3f);
320 }
321 else
322 {
323 setSize(0.6f, 1.8f);
324 }
325}
326
327void Skeleton::readAdditionalSaveData(CompoundTag *tag)
328{
329 Monster::readAdditionalSaveData(tag);
330
331 if (tag->contains(L"SkeletonType"))
332 {
333 int value = tag->getByte(L"SkeletonType");
334 setSkeletonType(value);
335 }
336
337 reassessWeaponGoal();
338}
339
340void Skeleton::addAdditonalSaveData(CompoundTag *entityTag)
341{
342 Monster::addAdditonalSaveData(entityTag);
343 entityTag->putByte(L"SkeletonType", (byte) getSkeletonType());
344}
345
346void Skeleton::setEquippedSlot(int slot, shared_ptr<ItemInstance> item)
347{
348 Monster::setEquippedSlot(slot, item);
349
350 if (!level->isClientSide && slot == SLOT_WEAPON)
351 {
352 reassessWeaponGoal();
353 }
354}
355
356double Skeleton::getRidingHeight()
357{
358 return Monster::getRidingHeight() - .5;
359}