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 "com.mojang.nbt.h"
3#include "net.minecraft.world.level.tile.h"
4#include "net.minecraft.world.phys.h"
5#include "net.minecraft.world.level.h"
6#include "net.minecraft.world.item.h"
7#include "net.minecraft.world.entity.h"
8#include "net.minecraft.world.entity.animal.h"
9#include "net.minecraft.world.entity.ai.attributes.h"
10#include "net.minecraft.world.entity.ai.goal.h"
11#include "net.minecraft.world.entity.ai.goal.target.h"
12#include "net.minecraft.world.entity.ai.navigation.h"
13#include "net.minecraft.world.entity.monster.h"
14#include "net.minecraft.world.entity.player.h"
15#include "net.minecraft.world.entity.projectile.h"
16#include "net.minecraft.world.level.pathfinder.h"
17#include "net.minecraft.world.damagesource.h"
18#include "net.minecraft.stats.h"
19#include "Sheep.h"
20#include "Wolf.h"
21#include "..\Minecraft.Client\Textures.h"
22#include "SoundTypes.h"
23
24
25
26Wolf::Wolf(Level *level) : TamableAnimal( level )
27{
28 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that
29 // the derived version of the function is called
30 this->defineSynchedData();
31 registerAttributes();
32 setHealth(getMaxHealth());
33
34 interestedAngle = interestedAngleO = 0.0f;
35 m_isWet = isShaking = false;
36 shakeAnim = shakeAnimO = 0.0f;
37
38 this->setSize(0.60f, 0.8f);
39
40 getNavigation()->setAvoidWater(true);
41 goalSelector.addGoal(1, new FloatGoal(this));
42 goalSelector.addGoal(2, sitGoal, false);
43 goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4));
44 goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true));
45 goalSelector.addGoal(5, new FollowOwnerGoal(this, 1.0, 10, 2));
46 goalSelector.addGoal(6, new BreedGoal(this, 1.0));
47 goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0));
48 goalSelector.addGoal(8, new BegGoal(this, 8));
49 goalSelector.addGoal(9, new LookAtPlayerGoal(this, typeid(Player), 8));
50 goalSelector.addGoal(9, new RandomLookAroundGoal(this));
51
52 targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this));
53 targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
54 targetSelector.addGoal(3, new HurtByTargetGoal(this, true));
55 targetSelector.addGoal(4, new NonTameRandomTargetGoal(this, typeid(Sheep), 200, false));
56
57 setTame(false); // Initialize health
58}
59
60void Wolf::registerAttributes()
61{
62 TamableAnimal::registerAttributes();
63
64 getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f);
65
66 if (isTame())
67 {
68 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(TAME_HEALTH);
69 }
70 else
71 {
72 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(START_HEALTH);
73 }
74}
75
76bool Wolf::useNewAi()
77{
78 return true;
79}
80
81void Wolf::setTarget(shared_ptr<LivingEntity> target)
82{
83 TamableAnimal::setTarget(target);
84 if ( target == NULL )
85 {
86 setAngry(false);
87 }
88 else if(!isTame())
89 {
90 setAngry(true);
91 }
92}
93
94void Wolf::serverAiMobStep()
95{
96 entityData->set(DATA_HEALTH_ID, getHealth());
97}
98
99void Wolf::defineSynchedData()
100{
101 TamableAnimal::defineSynchedData();
102 entityData->define(DATA_HEALTH_ID, getHealth());
103 entityData->define(DATA_INTERESTED_ID, (byte)0);
104 entityData->define(DATA_COLLAR_COLOR, (byte) ColoredTile::getTileDataForItemAuxValue(DyePowderItem::RED));
105}
106
107void Wolf::playStepSound(int xt, int yt, int zt, int t)
108{
109 playSound(eSoundType_MOB_WOLF_STEP, 0.15f, 1);
110}
111
112void Wolf::addAdditonalSaveData(CompoundTag *tag)
113{
114 TamableAnimal::addAdditonalSaveData(tag);
115
116 tag->putBoolean(L"Angry", isAngry());
117 tag->putByte(L"CollarColor", (byte) getCollarColor());
118}
119
120void Wolf::readAdditionalSaveData(CompoundTag *tag)
121{
122 TamableAnimal::readAdditionalSaveData(tag);
123
124 setAngry(tag->getBoolean(L"Angry"));
125 if (tag->contains(L"CollarColor")) setCollarColor(tag->getByte(L"CollarColor"));
126}
127
128int Wolf::getAmbientSound()
129{
130 if (isAngry())
131 {
132 return eSoundType_MOB_WOLF_GROWL;
133 }
134 if (random->nextInt(3) == 0)
135 {
136 if (isTame() && entityData->getFloat(DATA_HEALTH_ID) < 10)
137 {
138 return eSoundType_MOB_WOLF_WHINE;
139 }
140 return eSoundType_MOB_WOLF_PANTING;
141 }
142 return eSoundType_MOB_WOLF_BARK;
143}
144
145int Wolf::getHurtSound()
146{
147 return eSoundType_MOB_WOLF_HURT;
148}
149
150int Wolf::getDeathSound()
151{
152 return eSoundType_MOB_WOLF_DEATH;
153}
154
155float Wolf::getSoundVolume()
156{
157 return 0.4f;
158}
159
160int Wolf::getDeathLoot()
161{
162 return -1;
163}
164
165void Wolf::aiStep()
166{
167 TamableAnimal::aiStep();
168
169 if (!level->isClientSide && m_isWet && !isShaking && !isPathFinding() && onGround)
170 {
171 isShaking = true;
172 shakeAnim = 0;
173 shakeAnimO = 0;
174
175 level->broadcastEntityEvent(shared_from_this(), EntityEvent::SHAKE_WETNESS);
176 }
177}
178
179void Wolf::tick()
180{
181 TamableAnimal::tick();
182
183 interestedAngleO = interestedAngle;
184 if (isInterested())
185 {
186 interestedAngle = interestedAngle + (1 - interestedAngle) * 0.4f;
187 }
188 else
189 {
190 interestedAngle = interestedAngle + (0 - interestedAngle) * 0.4f;
191 }
192 if (isInterested())
193 {
194 lookTime = 10;
195 }
196
197 if (isInWaterOrRain())
198 {
199 m_isWet = true;
200 isShaking = false;
201 shakeAnim = 0;
202 shakeAnimO = 0;
203 }
204 else if (m_isWet || isShaking)
205 {
206 if (isShaking)
207 {
208
209 if (shakeAnim == 0)
210 {
211 playSound(eSoundType_MOB_WOLF_SHAKE, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
212 }
213
214 shakeAnimO = shakeAnim;
215 shakeAnim += 0.05f;
216
217 if (shakeAnimO >= 2)
218 {
219 m_isWet = false;
220 isShaking = false;
221 shakeAnimO = 0;
222 shakeAnim = 0;
223 }
224
225 if (shakeAnim > 0.4f)
226 {
227 float yt = (float) bb->y0;
228 int shakeCount = (int) (Mth::sin((shakeAnim - 0.4f) * PI) * 7.0f);
229 for (int i = 0; i < shakeCount; i++)
230 {
231 float xo = (random->nextFloat() * 2 - 1) * bbWidth * 0.5f;
232 float zo = (random->nextFloat() * 2 - 1) * bbWidth * 0.5f;
233 level->addParticle(eParticleType_splash, x + xo, yt + 0.8f, z + zo, xd, yd, zd);
234 }
235 }
236 }
237 }
238}
239
240bool Wolf::isWet()
241{
242 return m_isWet;
243}
244
245float Wolf::getWetShade(float a)
246{
247 return 0.75f + ((shakeAnimO + (shakeAnim - shakeAnimO) * a) / 2.0f) * 0.25f;
248}
249
250float Wolf::getBodyRollAngle(float a, float offset)
251{
252 float progress = ((shakeAnimO + (shakeAnim - shakeAnimO) * a) + offset) / 1.8f;
253 if (progress < 0)
254 {
255 progress = 0;
256 }
257 else if (progress > 1)
258 {
259 progress = 1;
260 }
261 return Mth::sin(progress * PI) * Mth::sin(progress * PI * 11.0f) * 0.15f * PI;
262}
263
264float Wolf::getHeadRollAngle(float a)
265{
266 return (interestedAngleO + (interestedAngle - interestedAngleO) * a) * 0.15f * PI;
267}
268
269float Wolf::getHeadHeight()
270{
271 return bbHeight * 0.8f;
272}
273
274int Wolf::getMaxHeadXRot()
275{
276 if (isSitting())
277 {
278 return 20;
279 }
280 return TamableAnimal::getMaxHeadXRot();
281}
282
283bool Wolf::hurt(DamageSource *source, float dmg)
284{
285 // 4J: Protect owned wolves from untrusted players
286 if (isTame())
287 {
288 shared_ptr<Entity> entity = source->getDirectEntity();
289 if (entity != NULL && entity->instanceof(eTYPE_PLAYER))
290 {
291 shared_ptr<Player> attacker = dynamic_pointer_cast<Player>(entity);
292 attacker->canHarmPlayer(getOwnerUUID());
293 }
294 }
295
296 if (isInvulnerable()) return false;
297 shared_ptr<Entity> sourceEntity = source->getEntity();
298 sitGoal->wantToSit(false);
299 if (sourceEntity != NULL && !(sourceEntity->instanceof(eTYPE_PLAYER) || sourceEntity->instanceof(eTYPE_ARROW)))
300 {
301 // Take half damage from non-players and arrows
302 dmg = (dmg + 1) / 2;
303 }
304 return TamableAnimal::hurt(source, dmg);
305}
306
307bool Wolf::doHurtTarget(shared_ptr<Entity> target)
308{
309 int damage = isTame() ? 4 : 2;
310 return target->hurt(DamageSource::mobAttack(dynamic_pointer_cast<Mob>(shared_from_this())), damage);
311}
312
313void Wolf::setTame(bool value)
314{
315 TamableAnimal::setTame(value);
316
317 if (value)
318 {
319 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(TAME_HEALTH);
320 }
321 else
322 {
323 getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(START_HEALTH);
324 }
325}
326
327void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool bSetSitting)
328{
329 setTame(true);
330 setPath(NULL);
331 setTarget(nullptr);
332 sitGoal->wantToSit(bSetSitting);
333 setHealth(TAME_HEALTH);
334
335 setOwnerUUID(wsOwnerUUID);
336
337 // We'll not show the taming particles if this is a baby wolf
338 spawnTamingParticles(bDisplayTamingParticles);
339}
340
341bool Wolf::mobInteract(shared_ptr<Player> player)
342{
343 shared_ptr<ItemInstance> item = player->inventory->getSelected();
344
345 if (isTame())
346 {
347 if (item != NULL)
348 {
349 if(dynamic_cast<FoodItem *>(Item::items[item->id]) != NULL)
350 {
351 FoodItem *food = dynamic_cast<FoodItem *>( Item::items[item->id] );
352
353 if (food->isMeat() && entityData->getFloat(DATA_HEALTH_ID) < MAX_HEALTH)
354 {
355 heal(food->getNutrition());
356 // 4J-PB - don't lose the bone in creative mode
357 if (player->abilities.instabuild==false)
358 {
359 item->count--;
360 if (item->count <= 0)
361 {
362 player->inventory->setItem(player->inventory->selected, nullptr);
363 }
364 }
365 return true;
366 }
367 }
368 else if (item->id == Item::dye_powder_Id)
369 {
370 int color = ColoredTile::getTileDataForItemAuxValue(item->getAuxValue());
371 if (color != getCollarColor())
372 {
373 setCollarColor(color);
374
375 if (!player->abilities.instabuild && --item->count <= 0)
376 {
377 player->inventory->setItem(player->inventory->selected, nullptr);
378 }
379
380 return true;
381 }
382 }
383 }
384 if (equalsIgnoreCase(player->getUUID(), getOwnerUUID()))
385 {
386 if (!level->isClientSide && !isFood(item))
387 {
388 sitGoal->wantToSit(!isSitting());
389 jumping = false;
390 setPath(NULL);
391 setAttackTarget(nullptr);
392 setTarget(nullptr);
393 }
394 }
395 }
396 else
397 {
398 if (item != NULL && item->id == Item::bone->id && !isAngry())
399 {
400 // 4J-PB - don't lose the bone in creative mode
401 if (player->abilities.instabuild==false)
402 {
403 item->count--;
404 if (item->count <= 0)
405 {
406 player->inventory->setItem(player->inventory->selected, nullptr);
407 }
408 }
409
410 if (!level->isClientSide)
411 {
412 if (random->nextInt(3) == 0)
413 {
414 // 4J : WESTY: Added for new acheivements.
415 player->awardStat(GenericStats::tamedEntity(eTYPE_WOLF),GenericStats::param_tamedEntity(eTYPE_WOLF));
416
417 // 4J Changed to this
418 tame(player->getUUID(),true,true);
419
420 level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_SUCCEEDED);
421 }
422 else
423 {
424 spawnTamingParticles(false);
425 level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_FAILED);
426 }
427 }
428
429 return true;
430 }
431
432 // 4J-PB - stop wild wolves going in to Love Mode (even though they do on Java, but don't breed)
433 if((item != NULL) && isFood(item))
434 {
435 return false;
436 }
437 }
438 return TamableAnimal::mobInteract(player);
439}
440
441void Wolf::handleEntityEvent(byte id)
442{
443 if (id == EntityEvent::SHAKE_WETNESS)
444 {
445 isShaking = true;
446 shakeAnim = 0;
447 shakeAnimO = 0;
448 }
449 else
450 {
451 TamableAnimal::handleEntityEvent(id);
452 }
453}
454
455float Wolf::getTailAngle()
456{
457 if (isAngry())
458 {
459 return 0.49f * PI;
460 }
461 else if (isTame())
462 {
463 return (0.55f - (MAX_HEALTH - entityData->getFloat(DATA_HEALTH_ID)) * 0.02f) * PI;
464 }
465 return 0.20f * PI;
466}
467
468bool Wolf::isFood(shared_ptr<ItemInstance> item)
469{
470 if (item == NULL) return false;
471 if (dynamic_cast<FoodItem *>(Item::items[item->id]) == NULL) return false;
472 return ((FoodItem *) Item::items[item->id])->isMeat();
473}
474
475int Wolf::getMaxSpawnClusterSize()
476{
477 // 4J - changed - was 8 but we have a limit of only 8 wolves in the world so doesn't seem right potentially spawning them all in once cluster
478 return 4;
479}
480
481bool Wolf::isAngry()
482{
483 return (entityData->getByte(DATA_FLAGS_ID) & 0x02) != 0;
484}
485
486void Wolf::setAngry(bool value)
487{
488 byte current = entityData->getByte(DATA_FLAGS_ID);
489 if (value)
490 {
491 entityData->set(DATA_FLAGS_ID, (byte) (current | 0x02));
492 }
493 else
494 {
495 entityData->set(DATA_FLAGS_ID, (byte) (current & ~0x02));
496 }
497}
498
499int Wolf::getCollarColor()
500{
501 return entityData->getByte(DATA_COLLAR_COLOR) & 0xF;
502}
503
504void Wolf::setCollarColor(int color)
505{
506 entityData->set(DATA_COLLAR_COLOR, (byte) (color & 0xF));
507}
508
509// 4J-PB added for tooltips
510int Wolf::GetSynchedHealth()
511{
512 return getEntityData()->getInteger(DATA_HEALTH_ID);
513}
514
515shared_ptr<AgableMob> Wolf::getBreedOffspring(shared_ptr<AgableMob> target)
516{
517 // 4J - added limit to wolves that can be bred
518 if( level->canCreateMore( GetType(), Level::eSpawnType_Breed) )
519 {
520 shared_ptr<Wolf> pBabyWolf = shared_ptr<Wolf>( new Wolf(level) );
521
522 if(!getOwnerUUID().empty())
523 {
524 // set the baby wolf to be tame, and assign the owner
525 pBabyWolf->tame(getOwnerUUID(),false,false);
526 }
527 return pBabyWolf;
528 }
529 else
530 {
531 return nullptr;
532 }
533}
534
535void Wolf::setIsInterested(bool value)
536{
537 if (value)
538 {
539 entityData->set(DATA_INTERESTED_ID, (byte) 1);
540 }
541 else
542 {
543 entityData->set(DATA_INTERESTED_ID, (byte) 0);
544 }
545}
546
547bool Wolf::canMate(shared_ptr<Animal> animal)
548{
549 if (animal == shared_from_this()) return false;
550 if (!isTame()) return false;
551
552 if (!animal->instanceof(eTYPE_WOLF)) return false;
553 shared_ptr<Wolf> partner = dynamic_pointer_cast<Wolf>(animal);
554
555 if (partner == NULL) return false;
556 if (!partner->isTame()) return false;
557 if (partner->isSitting()) return false;
558
559 return isInLove() && partner->isInLove();
560}
561
562bool Wolf::isInterested()
563{
564 return entityData->getByte(DATA_INTERESTED_ID) == 1;
565}
566
567bool Wolf::removeWhenFarAway()
568{
569 return !isTame() && tickCount > SharedConstants::TICKS_PER_SECOND * 60 * 2;
570}
571
572bool Wolf::wantsToAttack(shared_ptr<LivingEntity> target, shared_ptr<LivingEntity> owner)
573{
574 // filter un-attackable mobs
575 if (target->GetType() == eTYPE_CREEPER || target->GetType() == eTYPE_GHAST)
576 {
577 return false;
578 }
579 // never target wolves that has this player as owner
580 if (target->GetType() == eTYPE_WOLF)
581 {
582 shared_ptr<Wolf> wolfTarget = dynamic_pointer_cast<Wolf>(target);
583 if (wolfTarget->isTame() && wolfTarget->getOwner() == owner)
584 {
585 return false;
586 }
587 }
588 if ( target->instanceof(eTYPE_PLAYER) && owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(owner)->canHarmPlayer(dynamic_pointer_cast<Player>(target) ))
589 {
590 // pvp is off
591 return false;
592 }
593 // don't attack tame horses
594 if ((target->GetType() == eTYPE_HORSE) && dynamic_pointer_cast<EntityHorse>(target)->isTamed())
595 {
596 return false;
597 }
598 return true;
599}