the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 489 lines 12 kB view raw
1#include "stdafx.h" 2 3#include "com.mojang.nbt.h" 4#include "net.minecraft.world.level.tile.h" 5#include "net.minecraft.world.item.h" 6#include "net.minecraft.world.phys.h" 7#include "net.minecraft.world.level.h" 8#include "net.minecraft.world.level.storage.h" 9#include "net.minecraft.world.entity.player.h" 10#include "net.minecraft.world.entity.h" 11#include "net.minecraft.world.entity.projectile.h" 12#include "net.minecraft.world.damagesource.h" 13#include "net.minecraft.world.entity.monster.h" 14#include "net.minecraft.world.entity.ai.attributes.h" 15#include "Random.h" 16#include "Animal.h" 17 18Animal::Animal(Level *level) : AgableMob( level ) 19{ 20// inLove = 0; // 4J removed - now synched data 21 loveTime = 0; 22 loveCause = shared_ptr<Player>(); 23 24 setDespawnProtected(); 25} 26 27void Animal::defineSynchedData() 28{ 29 AgableMob::defineSynchedData(); 30 31 entityData->define(DATA_IN_LOVE, (int)0); // 4J added 32} 33 34void Animal::serverAiMobStep() 35{ 36 if (getAge() != 0) setInLoveValue(0); 37 AgableMob::serverAiMobStep(); 38} 39 40 41void Animal::aiStep() 42{ 43 AgableMob::aiStep(); 44 45 if (getAge() != 0) setInLoveValue(0); 46 47 if (getInLoveValue() > 0) 48 { 49 setInLoveValue(getInLoveValue()-1); 50 if (getInLoveValue() % 10 == 0) 51 { 52 double xa = random->nextGaussian() * 0.02; 53 double ya = random->nextGaussian() * 0.02; 54 double za = random->nextGaussian() * 0.02; 55 level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); 56 } 57 } 58 else 59 { 60 loveTime = 0; 61 } 62 63 updateDespawnProtectedState(); // 4J added 64} 65 66void Animal::checkHurtTarget(shared_ptr<Entity> target, float d) 67{ 68 // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF 69 if ( target->instanceof(eTYPE_PLAYER) ) 70 { 71 if (d < 3) 72 { 73 double xd = target->x - x; 74 double zd = target->z - z; 75 yRot = (float) (atan2(zd, xd) * 180 / PI) - 90; 76 77 holdGround = true; 78 } 79 80 shared_ptr<Player> p = dynamic_pointer_cast<Player>(target); 81 if (p->getSelectedItem() == NULL || !isFood(p->getSelectedItem())) 82 { 83 attackTarget = nullptr; 84 } 85 86 } 87 // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF 88 else if ( target->instanceof(eTYPE_ANIMAL) ) 89 { 90 shared_ptr<Animal> a = dynamic_pointer_cast<Animal>(target); 91 if (getAge() > 0 && a->getAge() < 0) 92 { 93 if (d < 2.5) 94 { 95 holdGround = true; 96 } 97 } 98 else if (getInLoveValue() > 0 && a->getInLoveValue() > 0) 99 { 100 if (a->attackTarget == NULL) a->attackTarget = shared_from_this(); 101 102 if (a->attackTarget == shared_from_this() && d < 3.5) 103 { 104 a->setInLoveValue(a->getInLoveValue()+1); 105 setInLoveValue(getInLoveValue()+1); 106 loveTime++; 107 if (loveTime % 4 == 0) 108 { 109 level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, 0, 0, 0); 110 } 111 112 if (loveTime == 20 * 3) breedWith(a); 113 } 114 else loveTime = 0; 115 } 116 else 117 { 118 loveTime = 0; 119 attackTarget = nullptr; 120 } 121 122 } 123} 124 125 126void Animal::breedWith(shared_ptr<Animal> target) 127{ 128 shared_ptr<AgableMob> offspring = getBreedOffspring(target); 129 130 setInLoveValue(0); 131 loveTime = 0; 132 attackTarget = nullptr; 133 target->attackTarget = nullptr; 134 target->loveTime = 0; 135 target->setInLoveValue(0); 136 137 // 4J - we have offspring of NULL returned when we have hit our limits of spawning any particular type of animal. In these cases try and do everything we can apart from actually 138 // spawning the entity. 139 if (offspring != NULL) 140 { 141 // Only want to set the age to this +ve value if something is actually spawned, as during this period the animal will attempt to follow offspring and ignore players. 142 setAge(5 * 60 * 20); 143 target->setAge(5 * 60 * 20); 144 145 offspring->setAge(-20 * 60 * 20); 146 offspring->moveTo(x, y, z, yRot, xRot); 147 offspring->setDespawnProtected(); 148 for (int i = 0; i < 7; i++) 149 { 150 double xa = random->nextGaussian() * 0.02; 151 double ya = random->nextGaussian() * 0.02; 152 double za = random->nextGaussian() * 0.02; 153 level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); 154 } 155 level->addEntity(offspring); 156 157 level->addEntity( shared_ptr<ExperienceOrb>( new ExperienceOrb(level, x, y, z, random->nextInt(4) + 1) ) ); 158 } 159 160 setDespawnProtected(); 161} 162 163float Animal::getWalkTargetValue(int x, int y, int z) 164{ 165 if (level->getTile(x, y - 1, z) == Tile::grass_Id) return 10; 166 return level->getBrightness(x, y, z) - 0.5f; 167} 168 169bool Animal::hurt(DamageSource *dmgSource, float dmg) 170{ 171 if (isInvulnerable()) return false; 172 if (dynamic_cast<EntityDamageSource *>(dmgSource) != NULL) 173 { 174 shared_ptr<Entity> source = dmgSource->getDirectEntity(); 175 176 // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF 177 if ( source->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(source)->isAllowedToAttackAnimals() ) 178 { 179 return false; 180 } 181 182 if ( (source != NULL) && source->instanceof(eTYPE_ARROW) ) 183 { 184 shared_ptr<Arrow> arrow = dynamic_pointer_cast<Arrow>(source); 185 186 // 4J: Check that the arrow's owner can attack animals (dispenser arrows are not owned) 187 if (arrow->owner != NULL && arrow->owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(arrow->owner)->isAllowedToAttackAnimals() ) 188 { 189 return false; 190 } 191 } 192 } 193 194 fleeTime = 20 * 3; 195 196 if (!useNewAi()) 197 { 198 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); 199 if (speed->getModifier(eModifierId_MOB_FLEEING) == NULL) 200 { 201 speed->addModifier(new AttributeModifier(*Animal::SPEED_MODIFIER_FLEEING)); 202 } 203 } 204 205 attackTarget = nullptr; 206 setInLoveValue(0); 207 208 return AgableMob::hurt(dmgSource, dmg); 209} 210 211void Animal::addAdditonalSaveData(CompoundTag *tag) 212{ 213 AgableMob::addAdditonalSaveData(tag); 214 tag->putInt(L"InLove", getInLoveValue()); 215} 216 217void Animal::readAdditionalSaveData(CompoundTag *tag) 218{ 219 AgableMob::readAdditionalSaveData(tag); 220 setInLoveValue(tag->getInt(L"InLove")); 221 setDespawnProtected(); 222} 223 224shared_ptr<Entity> Animal::findAttackTarget() 225{ 226 if (fleeTime > 0) return nullptr; 227 228 float r = 8; 229 if (getInLoveValue() > 0) 230 { 231 vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r)); 232 //for (int i = 0; i < others->size(); i++) 233 for(AUTO_VAR(it, others->begin()); it != others->end(); ++it) 234 { 235 shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it); 236 if (p != shared_from_this() && p->getInLoveValue() > 0) 237 { 238 delete others; 239 return p; 240 } 241 } 242 delete others; 243 } 244 else 245 { 246 if (getAge() == 0) 247 { 248 vector<shared_ptr<Entity> > *players = level->getEntitiesOfClass(typeid(Player), bb->grow(r, r, r)); 249 //for (int i = 0; i < players.size(); i++) 250 for(AUTO_VAR(it, players->begin()); it != players->end(); ++it) 251 { 252 setDespawnProtected(); 253 254 shared_ptr<Player> p = dynamic_pointer_cast<Player>(*it); 255 if (p->getSelectedItem() != NULL && this->isFood(p->getSelectedItem())) 256 { 257 delete players; 258 return p; 259 } 260 } 261 delete players; 262 } 263 else if (getAge() > 0) 264 { 265 vector<shared_ptr<Entity> > *others = level->getEntitiesOfClass(typeid(*this), bb->grow(r, r, r)); 266 //for (int i = 0; i < others.size(); i++) 267 for(AUTO_VAR(it, others->begin()); it != others->end(); ++it) 268 { 269 shared_ptr<Animal> p = dynamic_pointer_cast<Animal>(*it); 270 if (p != shared_from_this() && p->getAge() < 0) 271 { 272 delete others; 273 return p; 274 } 275 } 276 delete others; 277 } 278 } 279 return nullptr; 280} 281 282bool Animal::canSpawn() 283{ 284 int xt = Mth::floor(x); 285 int yt = Mth::floor(bb->y0); 286 int zt = Mth::floor(z); 287 return level->getTile(xt, yt - 1, zt) == Tile::grass_Id && level->getDaytimeRawBrightness(xt, yt, zt) > 8 && AgableMob::canSpawn(); 288} 289 290int Animal::getAmbientSoundInterval() 291{ 292 return 20 * 6; 293} 294 295bool Animal::removeWhenFarAway() 296{ 297 return !isDespawnProtected(); // 4J changed - was false 298} 299 300int Animal::getExperienceReward(shared_ptr<Player> killedBy) 301{ 302 return 1 + level->random->nextInt(3); 303} 304 305bool Animal::isFood(shared_ptr<ItemInstance> itemInstance) 306{ 307 return itemInstance->id == Item::wheat_Id; 308} 309 310bool Animal::mobInteract(shared_ptr<Player> player) 311{ 312 shared_ptr<ItemInstance> item = player->inventory->getSelected(); 313 if (item != NULL && isFood(item) && getAge() == 0 && getInLoveValue() <= 0) 314 { 315 if (!player->abilities.instabuild) 316 { 317 item->count--; 318 if (item->count <= 0) 319 { 320 player->inventory->setItem(player->inventory->selected, nullptr); 321 } 322 } 323 324 325 // 4J-PB - If we can't produce another animal through breeding because of the spawn limits, display a message here 326 if(!level->isClientSide) 327 { 328 switch(GetType()) 329 { 330 case eTYPE_CHICKEN: 331 if( !level->canCreateMore(eTYPE_CHICKEN, Level::eSpawnType_Breed) ) 332 { 333 player->displayClientMessage(IDS_MAX_CHICKENS_BRED ); 334 return false; 335 } 336 break; 337 case eTYPE_WOLF: 338 if( !level->canCreateMore(eTYPE_WOLF, Level::eSpawnType_Breed) ) 339 { 340 player->displayClientMessage(IDS_MAX_WOLVES_BRED ); 341 return false; 342 } 343 break; 344 case eTYPE_MUSHROOMCOW: 345 if( !level->canCreateMore(eTYPE_MUSHROOMCOW, Level::eSpawnType_Breed) ) 346 { 347 player->displayClientMessage(IDS_MAX_MUSHROOMCOWS_BRED ); 348 return false; 349 } 350 break; 351 default: 352 if((GetType() & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) 353 { 354 if( !level->canCreateMore(GetType(), Level::eSpawnType_Breed) ) 355 { 356 player->displayClientMessage(IDS_MAX_PIGS_SHEEP_COWS_CATS_BRED ); 357 358 return false; 359 } 360 } 361 else if( instanceof(eTYPE_MONSTER) ) 362 { 363 364 } 365 break; 366 } 367 setInLove(player); 368 } 369 setInLove(); 370 371 return true; 372 } 373 return AgableMob::mobInteract(player); 374} 375 376// 4J added 377int Animal::getInLoveValue() 378{ 379 return entityData->getInteger(DATA_IN_LOVE); 380} 381 382void Animal::setInLoveValue(int value) 383{ 384 entityData->set(DATA_IN_LOVE, value); 385} 386 387// 4J added 388void Animal::setInLove(shared_ptr<Player> player) 389{ 390 loveCause = player; 391 setInLoveValue(20*30); 392} 393 394shared_ptr<Player> Animal::getLoveCause() 395{ 396 return loveCause.lock(); 397} 398 399void Animal::setInLove() 400{ 401 entityData->set(DATA_IN_LOVE, 20 * 30); 402 403 attackTarget = nullptr; 404 level->broadcastEntityEvent(shared_from_this(), EntityEvent::IN_LOVE_HEARTS); 405} 406 407bool Animal::isInLove() 408{ 409 return entityData->getInteger(DATA_IN_LOVE) > 0; 410} 411 412void Animal::resetLove() { 413 entityData->set(DATA_IN_LOVE, 0); 414} 415 416bool Animal::canMate(shared_ptr<Animal> partner) 417{ 418 if (partner == shared_from_this()) return false; 419 if (typeid(*partner) != typeid(*this)) return false; 420 return isInLove() && partner->isInLove(); 421} 422 423void Animal::handleEntityEvent(byte id) 424{ 425 if (id == EntityEvent::IN_LOVE_HEARTS) 426 { 427 for (int i = 0; i < 7; i++) 428 { 429 double xa = random->nextGaussian() * 0.02; 430 double ya = random->nextGaussian() * 0.02; 431 double za = random->nextGaussian() * 0.02; 432 level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); 433 } 434 } 435 else 436 { 437 AgableMob::handleEntityEvent(id); 438 } 439} 440 441void Animal::updateDespawnProtectedState() 442{ 443 if( level->isClientSide ) return; 444 445 if( m_isDespawnProtected ) 446 { 447 int xt = Mth::floor(x); 448 int zt = Mth::floor(z); 449 450 if ( xt > m_maxWanderX ) m_maxWanderX = xt; 451 if ( xt < m_minWanderX ) m_minWanderX = xt; 452 if ( zt > m_maxWanderZ ) m_maxWanderZ = zt; 453 if ( zt < m_minWanderZ ) m_minWanderZ = zt; 454 455 if( ( ( m_maxWanderX - m_minWanderX ) > MAX_WANDER_DISTANCE ) || 456 ( ( m_maxWanderZ - m_minWanderZ ) > MAX_WANDER_DISTANCE ) ) 457 { 458// printf("Unprotecting : %d to %d, %d to %d\n", m_minWanderX, m_maxWanderX, m_minWanderZ, m_maxWanderZ ); 459 m_isDespawnProtected = false; 460 } 461 462/* 463 if( isExtraWanderingEnabled() ) 464 { 465 printf("%d: %d %d, %d\n",entityId,m_maxWanderX - m_minWanderX, m_maxWanderZ - m_minWanderZ, getWanderingQuadrant()); 466 } 467 */ 468 } 469} 470 471bool Animal::isDespawnProtected() 472{ 473 return m_isDespawnProtected; 474} 475 476void Animal::setDespawnProtected() 477{ 478 if( level && level->isClientSide ) return; 479 480 int xt = Mth::floor(x); 481 int zt = Mth::floor(z); 482 483 m_minWanderX = xt; 484 m_maxWanderX = xt; 485 m_minWanderZ = zt; 486 m_maxWanderZ = zt; 487 488 m_isDespawnProtected = true; 489}