the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 3153 lines 81 kB view raw
1// 4J TODO 2 3// All the instanceof s from Java have been converted to dynamic_cast in this file 4// Once all the classes are finished it may be that we do not need to use dynamic_cast 5// for every test and a simple virtual function should suffice. We probably only need 6// dynamic_cast to find one of the classes that an object derives from, and not to find 7// the derived class itself (which should own the virtual GetType function) 8 9#include "stdafx.h" 10#include "JavaMath.h" 11#include "net.minecraft.h" 12#include "net.minecraft.world.h" 13#include "net.minecraft.stats.h" 14#include "net.minecraft.world.level.h" 15#include "net.minecraft.world.level.chunk.h" 16#include "net.minecraft.world.phys.h" 17#include "net.minecraft.world.entity.h" 18#include "net.minecraft.world.entity.ai.attributes.h" 19#include "net.minecraft.world.entity.animal.h" 20#include "net.minecraft.world.entity.boss.h" 21#include "net.minecraft.world.entity.monster.h" 22#include "net.minecraft.world.entity.item.h" 23#include "net.minecraft.world.item.h" 24#include "net.minecraft.world.item.enchantment.h" 25#include "net.minecraft.world.level.dimension.h" 26#include "net.minecraft.world.level.material.h" 27#include "net.minecraft.world.level.tile.h" 28#include "net.minecraft.world.level.tile.entity.h" 29#include "net.minecraft.world.scores.h" 30#include "net.minecraft.world.scores.criteria.h" 31#include "net.minecraft.world.entity.projectile.h" 32#include "net.minecraft.world.inventory.h" 33#include "net.minecraft.world.damagesource.h" 34#include "net.minecraft.world.effect.h" 35#include "net.minecraft.world.food.h" 36#include "Inventory.h" 37#include "Player.h" 38#include "ParticleTypes.h" 39 40#include "..\Minecraft.Client\Textures.h" 41 42#include "..\Minecraft.Client\LocalPlayer.h" 43#include "..\Minecraft.Client\HumanoidModel.h" 44#include "SoundTypes.h" 45 46 47 48void Player::_init() 49{ 50 registerAttributes(); 51 setHealth(getMaxHealth()); 52 53 inventory = shared_ptr<Inventory>( new Inventory( this ) ); 54 55 userType = 0; 56 oBob = bob = 0.0f; 57 58 xCloakO = yCloakO = zCloakO = 0.0; 59 xCloak = yCloak = zCloak = 0.0; 60 61 m_isSleeping = false; 62 63 customTextureUrl = L""; 64 customTextureUrl2 = L""; 65 m_uiPlayerCurrentSkin=0; 66 67 bedPosition = NULL; 68 69 sleepCounter = 0; 70 deathFadeCounter=0; 71 72 bedOffsetX = bedOffsetY = bedOffsetZ = 0.0f; 73 stats = NULL; 74 75 respawnPosition = NULL; 76 respawnForced = false; 77 minecartAchievementPos = NULL; 78 79 fishing = nullptr; 80 81 distanceWalk = distanceSwim = distanceFall = distanceClimb = distanceMinecart = distanceBoat = distancePig = 0; 82 83 m_uiDebugOptions=0L; 84 85 jumpTriggerTime = 0; 86 takeXpDelay = 0; 87 experienceLevel = totalExperience = 0; 88 experienceProgress = 0.0f; 89 90 useItem = nullptr; 91 useItemDuration = 0; 92 93 defaultWalkSpeed = 0.1f; 94 defaultFlySpeed = 0.02f; 95 96 lastLevelUpTime = 0; 97 98 m_uiGamePrivileges = 0; 99 100 m_ppAdditionalModelParts=NULL; 101 m_bCheckedForModelParts=false; 102 m_bCheckedDLCForModelParts=false; 103 104#if defined(__PS3__) || defined(__ORBIS__) 105 m_ePlayerNameValidState=ePlayerNameValid_NotSet; 106#endif 107 108 enderChestInventory = shared_ptr<PlayerEnderChestContainer>(new PlayerEnderChestContainer()); 109 110 m_bAwardedOnARail=false; 111} 112 113Player::Player(Level *level, const wstring &name) : LivingEntity( level ) 114{ 115 // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that 116 // the derived version of the function is called 117 this->defineSynchedData(); 118 119 this->name = name; 120 121 _init(); 122 MemSect(11); 123 inventoryMenu = new InventoryMenu(inventory, !level->isClientSide, this); 124 MemSect(0); 125 126 containerMenu = inventoryMenu; 127 128 heightOffset = 1.62f; 129 Pos *spawnPos = level->getSharedSpawnPos(); 130 moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); 131 delete spawnPos; 132 133 rotOffs = 180; 134 flameTime = 20; 135 136 m_skinIndex = eDefaultSkins_Skin0; 137 m_playerIndex = 0; 138 m_dwSkinId = 0; 139 m_dwCapeId = 0; 140 141 // 4J Added 142 m_xuid = INVALID_XUID; 143 m_OnlineXuid = INVALID_XUID; 144 //m_bShownOnMaps = true; 145 setShowOnMaps(app.GetGameHostOption(eGameHostOption_Gamertags)!=0?true:false); 146 m_bIsGuest = false; 147 148#ifndef _XBOX_ONE 149 // 4J: Set UUID to name on none-XB1 consoles, may change in future but for now 150 // ownership of animals on these consoles is done by name 151 setUUID(name); 152#endif 153} 154 155Player::~Player() 156{ 157 // TODO 4J 158 //printf("A player has been destroyed.\n"); 159 delete inventoryMenu; 160 161 // 4J Stu - Fix for #10938 - CRASH - Game hardlocks when client has an open chest and Xbox Guide while host exits without saving. 162 // If the container menu is not the inventory menu, then the player has a menu open. These get deleted when the xui scene 163 // is destroyed, so we can not delete it here 164 //if( containerMenu != inventoryMenu ) delete containerMenu; 165} 166 167void Player::registerAttributes() 168{ 169 LivingEntity::registerAttributes(); 170 171 getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(1); 172} 173 174void Player::defineSynchedData() 175{ 176 LivingEntity::defineSynchedData(); 177 178 entityData->define(DATA_PLAYER_FLAGS_ID, (byte) 0); 179 entityData->define(DATA_PLAYER_ABSORPTION_ID, (float) 0); 180 entityData->define(DATA_SCORE_ID, (int) 0); 181} 182 183shared_ptr<ItemInstance> Player::getUseItem() 184{ 185 return useItem; 186} 187 188int Player::getUseItemDuration() 189{ 190 return useItemDuration; 191} 192 193bool Player::isUsingItem() 194{ 195 return useItem != NULL; 196} 197 198int Player::getTicksUsingItem() 199{ 200 if (isUsingItem()) 201 { 202 return useItem->getUseDuration() - useItemDuration; 203 } 204 return 0; 205} 206 207void Player::releaseUsingItem() 208{ 209 if (useItem != NULL) 210 { 211 useItem->releaseUsing(level, dynamic_pointer_cast<Player>( shared_from_this() ), useItemDuration); 212 213 // 4J Stu - Fix for various bugs where an incorrect bow was displayed when it broke (#70859,#93972,#93974) 214 if (useItem->count == 0) 215 { 216 removeSelectedItem(); 217 } 218 } 219 stopUsingItem(); 220} 221 222void Player::stopUsingItem() 223{ 224 useItem = nullptr; 225 useItemDuration = 0; 226 if (!level->isClientSide) 227 { 228 setUsingItemFlag(false); 229 } 230} 231 232bool Player::isBlocking() 233{ 234 return isUsingItem() && Item::items[useItem->id]->getUseAnimation(useItem) == UseAnim_block; 235} 236 237// 4J Stu - Added for things that should only be ticked once per simulation frame 238void Player::updateFrameTick() 239{ 240 if (useItem != NULL) 241 { 242 shared_ptr<ItemInstance> item = inventory->getSelected(); 243 // 4J Stu - Fix for #45508 - TU5: Gameplay: Eating one piece of food will result in a second piece being eaten as well 244 // Original code was item != useItem. Changed this now to use the equals function, and add the NULL check as well for the other possible not equals (useItem is not NULL if we are here) 245 // This is because the useItem and item could be different objects due to an inventory update from the server, but still be the same item (with the same id,count and auxvalue) 246 if (item == NULL || !item->equals(useItem) ) 247 { 248 stopUsingItem(); 249 } 250 else 251 { 252 if (useItemDuration <= 25 && useItemDuration % 4 == 0) 253 { 254 spawnEatParticles(item, 5); 255 } 256 if (--useItemDuration == 0) 257 { 258 if (!level->isClientSide) 259 { 260 completeUsingItem(); 261 } 262 } 263 } 264 } 265 266 if (takeXpDelay > 0) takeXpDelay--; 267 268 if (isSleeping()) 269 { 270 sleepCounter++; 271 if (sleepCounter > SLEEP_DURATION) 272 { 273 sleepCounter = SLEEP_DURATION; 274 } 275 276 if (!level->isClientSide) 277 { 278 if (!checkBed()) 279 { 280 stopSleepInBed(true, true, false); 281 } 282 else if (level->isDay()) 283 { 284 stopSleepInBed(false, true, true); 285 } 286 } 287 } 288 else if (sleepCounter > 0) 289 { 290 sleepCounter++; 291 if (sleepCounter >= (SLEEP_DURATION + WAKE_UP_DURATION)) 292 { 293 sleepCounter = 0; 294 } 295 } 296 297 if(!isAlive()) 298 { 299 deathFadeCounter++; 300 if (deathFadeCounter > DEATHFADE_DURATION) 301 { 302 deathFadeCounter = DEATHFADE_DURATION; 303 } 304 } 305} 306 307void Player::tick() 308{ 309 if(level->isClientSide) 310 { 311 // 4J Stu - Server player calls this differently so that it only happens once per simulation tick 312 updateFrameTick(); 313 } 314 315 LivingEntity::tick(); 316 317 if (!level->isClientSide) 318 { 319 if (containerMenu != NULL && !containerMenu->stillValid( dynamic_pointer_cast<Player>( shared_from_this() ) )) 320 { 321 closeContainer(); 322 containerMenu = inventoryMenu; 323 } 324 } 325 326 if (isOnFire() && (abilities.invulnerable || hasInvulnerablePrivilege() ) ) 327 { 328 clearFire(); 329 } 330 331 xCloakO = xCloak; 332 yCloakO = yCloak; 333 zCloakO = zCloak; 334 335 double xca = x - xCloak; 336 double yca = y - yCloak; 337 double zca = z - zCloak; 338 339 double m = 10; 340 if (xca > m) xCloakO = xCloak = x; 341 if (zca > m) zCloakO = zCloak = z; 342 if (yca > m) yCloakO = yCloak = y; 343 if (xca < -m) xCloakO = xCloak = x; 344 if (zca < -m) zCloakO = zCloak = z; 345 if (yca < -m) yCloakO = yCloak = y; 346 347 xCloak += xca * 0.25; 348 zCloak += zca * 0.25; 349 yCloak += yca * 0.25; 350 351 if (riding == NULL) 352 { 353 if( minecartAchievementPos != NULL ) 354 { 355 delete minecartAchievementPos; 356 minecartAchievementPos = NULL; 357 } 358 } 359 360 if (!level->isClientSide) 361 { 362 foodData.tick(dynamic_pointer_cast<Player>(shared_from_this())); 363 } 364 365 // 4J Stu Debugging 366 if (!level->isClientSide) 367 { 368 static int count = 0; 369 if( count++ == 100 ) 370 { 371#if 0 372#ifdef _WINDOWS64 373 // Drop some items so we have them in inventory to play with 374 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Tile::recordPlayer) ) ); 375 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::map) ) ); 376 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_01) ) ); 377 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_02) ) ); 378 this->drop( shared_ptr<ItemInstance>(new ItemInstance( Item::pickAxe_diamond, 1 )) ); 379#endif 380 381#ifdef __PS3__ 382 // #ifdef _DEBUG 383 // // Drop some items so we have them in inventory to play with 384 // this->drop( shared_ptr<ItemInstance>( new ItemInstance(Tile::recordPlayer) ) ); 385 // this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::map) ) ); 386 // this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_01) ) ); 387 // this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_02) ) ); 388 // this->drop( shared_ptr<ItemInstance>(new ItemInstance( Item::pickAxe_diamond, 1 )) ); 389 // #endif 390#endif 391 392#ifdef _DURANGO 393 // Drop some items so we have them in inventory to play with 394 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Tile::recordPlayer) ) ); 395 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::map) ) ); 396 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_01) ) ); 397 this->drop( shared_ptr<ItemInstance>( new ItemInstance(Item::record_02) ) ); 398 this->drop( shared_ptr<ItemInstance>(new ItemInstance( Item::pickAxe_diamond, 1 )) ); 399#endif 400#endif 401 // 4J-PB - Throw items out at the start of the level 402 //this->drop( new ItemInstance( Item::pickAxe_diamond, 1 ) ); 403 //this->drop( new ItemInstance( Tile::workBench, 1 ) ); 404 //this->drop( new ItemInstance( Tile::treeTrunk, 8 ) ); 405 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::milk, 3 ) ) ); 406 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::sugar, 2 ) ) ); 407 //this->drop( new ItemInstance( Tile::stoneBrick, 8 ) ); 408 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::wheat, 3 ) ) ); 409 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::egg, 1 ) ) ); 410 //this->drop( new ItemInstance( Item::bow, 1 ) ); 411 //this->drop( new ItemInstance( Item::arrow, 10 ) ); 412 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::saddle, 10 ) ) ); 413 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Tile::fence, 64 ) ) ); 414 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Tile::fence, 64 ) ) ); 415 //this->drop( shared_ptr<ItemInstance>( new ItemInstance( Tile::fence, 64 ) ) ); 416 417 418 //shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(Pig::_class->newInstance( level )); 419 //mob->moveTo(x+1, y, z+1, level->random->nextFloat() * 360, 0); 420 //level->addEntity(mob); 421 422 // 4J : WESTY : Spawn some wolves to befriend! 423 /* 424 shared_ptr<Mob> mob1 = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); 425 mob1->moveTo(x+1, y, z+1, level->random->nextFloat() * 360, 0); 426 level->addEntity(mob1); 427 428 shared_ptr<Mob> mob2 = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); 429 mob2->moveTo(x+2, y, z+1, level->random->nextFloat() * 360, 0); 430 level->addEntity(mob2); 431 432 shared_ptr<Mob> mob3 = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); 433 mob3->moveTo(x+1, y, z+2, level->random->nextFloat() * 360, 0); 434 level->addEntity(mob3); 435 436 shared_ptr<Mob> mob4 = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); 437 mob4->moveTo(x+3, y, z+1, level->random->nextFloat() * 360, 0); 438 level->addEntity(mob4); 439 440 shared_ptr<Mob> mob5 = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); 441 mob5->moveTo(x+1, y, z+3, level->random->nextFloat() * 360, 0); 442 level->addEntity(mob5); 443 */ 444 445 // inventory.add(new ItemInstance(Item.potion, 1, PotionBrewing.THROWABLE_MASK | 0xc)); 446 // addEffect(new MobEffectInstance(MobEffect.blindness.id, 60)); 447 // increaseXp(10); 448 449 { 450 // ItemInstance itemInstance = new ItemInstance(Item.pickAxe_diamond); 451 // itemInstance.enchant(Enchantment.diggingBonus, 3); 452 // inventory.add(itemInstance); 453 } 454 } 455#if 0 456 // 4J Stu - This makes a tunnel with a powered track just over length to get the On A Rail achievement 457 // It needs a few items at the start to get you going (a level and some powered rails) and of course a 458 // minecart. For some reason some of the torches come off so it will also need some fixing along the way. 459 static bool madeTrack = false; 460 if( !madeTrack ) 461 { 462 this->drop( shared_ptr<ItemInstance>( new ItemInstance( Item::minecart, 1 ) ) ); 463 this->drop( shared_ptr<ItemInstance>( new ItemInstance( Tile::goldenRail, 10 ) ) ); 464 this->drop( shared_ptr<ItemInstance>( new ItemInstance( Tile::lever, 10 ) ) ); 465 466 int poweredCount = 0; 467 for(int i = 10; i < 2800; ++i) 468 { 469 level->setTileAndData(x+i,y-1,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 470 level->setTileAndData(x+i,y,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 471 level->setTileAndData(x+i,y+1,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 472 level->setTileAndData(x+i,y+2,z-2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); 473 level->setTileAndData(x+i,y+3,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 474 475 level->setTileAndData(x+i,y-1,z-1,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); 476 if(i%20 == 0) 477 { 478 level->setTileAndData(x+i,y,z-1,Tile::redstoneTorch_on_Id,0,Tile::UPDATE_CLIENTS); 479 poweredCount = 4; 480 } 481 else 482 { 483 level->setTileAndData(x+i,y,z-1,0,0,Tile::UPDATE_CLIENTS); 484 } 485 level->setTileAndData(x+i,y+1,z-1,0,0,Tile::UPDATE_CLIENTS); 486 level->setTileAndData(x+i,y+2,z-1,0,0,Tile::UPDATE_CLIENTS); 487 level->setTileAndData(x+i,y+3,z-1,0,0,Tile::UPDATE_CLIENTS); 488 489 level->setTileAndData(x+i,y-1,z,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); 490 if(poweredCount>0) 491 { 492 level->setTileAndData(x+i,y,z,Tile::goldenRail_Id,0,Tile::UPDATE_CLIENTS); 493 --poweredCount; 494 } 495 else 496 { 497 level->setTileAndData(x+i,y,z,Tile::rail_Id,0,Tile::UPDATE_CLIENTS); 498 } 499 level->setTileAndData(x+i,y+1,z,0,0,Tile::UPDATE_CLIENTS); 500 level->setTileAndData(x+i,y+2,z,0,0,Tile::UPDATE_CLIENTS); 501 level->setTileAndData(x+i,y+3,z,0,0,Tile::UPDATE_CLIENTS); 502 503 level->setTileAndData(x+i,y-1,z+1,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); 504 if((i+5)%20 == 0) 505 { 506 level->setTileAndData(x+i,y,z+1,Tile::torch_Id,0,Tile::UPDATE_CLIENTS); 507 } 508 else 509 { 510 level->setTileAndData(x+i,y,z+1,0,0,Tile::UPDATE_CLIENTS); 511 } 512 level->setTileAndData(x+i,y+1,z+1,0,0,Tile::UPDATE_CLIENTS); 513 level->setTileAndData(x+i,y+2,z+1,0,0,Tile::UPDATE_CLIENTS); 514 level->setTileAndData(x+i,y+3,z+1,0,0,Tile::UPDATE_CLIENTS); 515 516 level->setTileAndData(x+i,y-1,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 517 level->setTileAndData(x+i,y,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 518 level->setTileAndData(x+i,y+1,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 519 level->setTileAndData(x+i,y+2,z+2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); 520 level->setTileAndData(x+i,y+3,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); 521 } 522 madeTrack = true; 523 } 524#endif 525 } 526 //End 4J sTU 527} 528 529int Player::getPortalWaitTime() 530{ 531 return abilities.invulnerable ? 0 : SharedConstants::TICKS_PER_SECOND * 4; 532} 533 534int Player::getDimensionChangingDelay() 535{ 536 return SharedConstants::TICKS_PER_SECOND / 2; 537} 538 539void Player::playSound(int iSound, float volume, float pitch) 540{ 541 // this sound method will play locally for the local player, and 542 // broadcast to remote players 543 level->playPlayerSound(dynamic_pointer_cast<Player>(shared_from_this()), iSound, volume, pitch); 544} 545 546void Player::spawnEatParticles(shared_ptr<ItemInstance> useItem, int count) 547{ 548 if (useItem->getUseAnimation() == UseAnim_drink) 549 { 550 playSound(eSoundType_RANDOM_DRINK, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); 551 } 552 if (useItem->getUseAnimation() == UseAnim_eat) 553 { 554 for (int i = 0; i < count; i++) 555 { 556 Vec3 *d = Vec3::newTemp((random->nextFloat() - 0.5) * 0.1, Math::random() * 0.1 + 0.1, 0); 557 558 d->xRot(-xRot * PI / 180); 559 d->yRot(-yRot * PI / 180); 560 561 Vec3 *p = Vec3::newTemp((random->nextFloat() - 0.5) * 0.3, -random->nextFloat() * 0.6 - 0.3, 0.6); 562 p->xRot(-xRot * PI / 180); 563 p->yRot(-yRot * PI / 180); 564 p = p->add(x, y + getHeadHeight(), z); 565 566 level->addParticle(PARTICLE_ICONCRACK(useItem->getItem()->id,0), p->x, p->y, p->z, d->x, d->y + 0.05, d->z); 567 } 568 569 // 4J Stu - Was L"mob.eat" which doesnt exist 570 playSound(eSoundType_RANDOM_EAT, 0.5f + 0.5f * random->nextInt(2), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); 571 } 572} 573 574void Player::completeUsingItem() 575{ 576 if (useItem != NULL) 577 { 578 spawnEatParticles(useItem, 16); 579 580 int oldCount = useItem->count; 581 shared_ptr<ItemInstance> itemInstance = useItem->useTimeDepleted(level, dynamic_pointer_cast<Player>(shared_from_this())); 582 if (itemInstance != useItem || (itemInstance != NULL && itemInstance->count != oldCount)) 583 { 584 inventory->items[inventory->selected] = itemInstance; 585 if (itemInstance->count == 0) 586 { 587 inventory->items[inventory->selected] = nullptr; 588 } 589 } 590 stopUsingItem(); 591 } 592} 593 594void Player::handleEntityEvent(byte id) 595{ 596 if (id == EntityEvent::USE_ITEM_COMPLETE) 597 { 598 completeUsingItem(); 599 } 600 else 601 { 602 LivingEntity::handleEntityEvent(id); 603 } 604} 605 606bool Player::isImmobile() 607{ 608 return getHealth() <= 0 || isSleeping(); 609} 610 611void Player::closeContainer() 612{ 613 containerMenu = inventoryMenu; 614} 615 616void Player::ride(shared_ptr<Entity> e) 617{ 618 if (riding != NULL && e == NULL) 619 { 620 if (!level->isClientSide) findStandUpPosition(riding); 621 622 if (riding != NULL) 623 { 624 riding->rider = weak_ptr<Entity>(); 625 } 626 riding = nullptr; 627 628 return; 629 } 630 LivingEntity::ride(e); 631} 632 633void Player::setPlayerDefaultSkin(EDefaultSkins skin) 634{ 635#ifndef _CONTENT_PACKAGE 636 wprintf(L"Setting default skin to %d for player %ls\n", skin, name.c_str() ); 637#endif 638 m_skinIndex = skin; 639} 640 641void Player::setCustomSkin(DWORD skinId) 642{ 643#ifndef _CONTENT_PACKAGE 644 wprintf(L"Attempting to set skin to %08X for player %ls\n", skinId, name.c_str() ); 645#endif 646 EDefaultSkins playerSkin = eDefaultSkins_ServerSelected; 647 648 // reset the idle 649 setIsIdle(false); 650 651 setAnimOverrideBitmask(getSkinAnimOverrideBitmask(skinId)); 652 if( !GET_IS_DLC_SKIN_FROM_BITMASK(skinId) ) 653 { 654 // GET_UGC_SKIN_ID_FROM_BITMASK will always be zero - this was for a possible custom skin editor skin 655 DWORD ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(skinId); 656 DWORD defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(skinId); 657 if( ugcSkinIndex == 0 && defaultSkinIndex > 0 ) 658 { 659 playerSkin = (EDefaultSkins) defaultSkinIndex; 660 } 661 } 662 663 if( playerSkin == eDefaultSkins_ServerSelected) 664 { 665 playerSkin = (EDefaultSkins)(m_playerIndex + 1); 666 } 667 668 // We always set a default skin, since we may be waiting for the player's custom skin to be transmitted 669 setPlayerDefaultSkin( playerSkin ); 670 671 m_dwSkinId = skinId; 672 this->customTextureUrl = app.getSkinPathFromId(skinId); 673 674 // set the new player additional boxes 675 /*vector<ModelPart *> *pvModelParts=app.GetAdditionalModelParts(m_dwSkinId); 676 677 if(pvModelParts==NULL) 678 { 679 // we don't have the data from the dlc skin yet 680 app.DebugPrintf("Couldn't get model parts for skin %X\n",m_dwSkinId); 681 682 // do we have it from the DLC pack? 683 DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(this->customTextureUrl); 684 685 if(pDLCSkinFile!=NULL) 686 { 687 DWORD dwBoxC=pDLCSkinFile->getAdditionalBoxesCount(); 688 if(dwBoxC!=0) 689 { 690 app.DebugPrintf("Got model parts from DLCskin for skin %X\n",m_dwSkinId); 691 pvModelParts=app.SetAdditionalSkinBoxes(m_dwSkinId,pDLCSkinFile->getAdditionalBoxes()); 692 this->SetAdditionalModelParts(pvModelParts); 693 } 694 else 695 { 696 this->SetAdditionalModelParts(NULL); 697 } 698 app.SetAnimOverrideBitmask(pDLCSkinFile->getSkinID(),pDLCSkinFile->getAnimOverrideBitmask()); 699 } 700 else 701 { 702 this->SetAdditionalModelParts(NULL); 703 } 704 } 705 else 706 { 707 app.DebugPrintf("Got model parts from app.GetAdditionalModelParts for skin %X\n",m_dwSkinId); 708 709 this->SetAdditionalModelParts(pvModelParts); 710 }*/ 711 712 // reset the check for model parts 713 m_bCheckedForModelParts=false; 714 m_bCheckedDLCForModelParts=false; 715 this->SetAdditionalModelParts(NULL); 716 717 718} 719 720unsigned int Player::getSkinAnimOverrideBitmask(DWORD skinId) 721{ 722 unsigned long bitmask = 0L; 723 if( GET_IS_DLC_SKIN_FROM_BITMASK(skinId) ) 724 { 725 // Temp check for anim override 726 switch( GET_DLC_SKIN_ID_FROM_BITMASK(skinId) ) 727 { 728 case 0x2://SP1_ZOMBIE: 729 case 0x3://SP1_HEROBRINE: 730 case 0xc8://SP3_ZOMBIE_PIGMAN: 731 case 0xc9://SP3_ZOMBIE_HEROBRINE: 732 case 0x1f8: // SPH_4JMUMMY 733 case 0x220: // SPH_AOT_MUMMY 734 case 0x23a: // SPH_CLIMAX_ZOMBIEBUSINESSMAN 735 case 0x23d: // SPH_CLIMAX_EVILROBOT 736 case 0x247: // SPH_CLIMAX_ZOMBIE 737 case 0x194: // SOA_DEADLIGHT_SKINNY_ZOMBIE 738 case 0x195: // SOA_DEADLIGHT_FEMALE_ZOMBIE 739 bitmask = 1<<HumanoidModel::eAnim_ArmsOutFront; 740 break; 741 case 0x1fa://SPH_GHOST: 742 bitmask = 1<<HumanoidModel::eAnim_ArmsOutFront | 1<<HumanoidModel::eAnim_NoLegAnim; 743 break; 744 case 0x1f4://SPH_GRIMREAPER: 745 bitmask = 1<<HumanoidModel::eAnim_ArmsDown | 1<<HumanoidModel::eAnim_NoLegAnim; 746 break; 747 case 0x1f7: // SPH_4J_FRANKENSTEIN 748 //bitmask = 1<<HumanoidModel::eAnim_HasIdle; 749 break; 750 break; 751 default: 752 // This is not one of the prefined skins 753 // Does the app have an anim override for this skin? 754 bitmask=app.GetAnimOverrideBitmask(skinId); 755 break; 756 } 757 } 758 return bitmask; 759} 760 761void Player::setXuid(PlayerUID xuid) 762{ 763 m_xuid = xuid; 764#ifdef _XBOX_ONE 765 // 4J Stu - For XboxOne (and probably in the future all other platforms) we store a UUID for the player to use as the owner key for tamed animals 766 // This should just be a string version of the xuid 767 768 setUUID( xuid.toString() ); 769#endif 770} 771 772void Player::setCustomCape(DWORD capeId) 773{ 774#ifndef _CONTENT_PACKAGE 775 wprintf(L"Attempting to set cape to %08X for player %s\n", capeId, name.c_str() ); 776#endif 777 778 m_dwCapeId = capeId; 779 780 if(capeId > 0) 781 { 782 this->customTextureUrl2 = Player::getCapePathFromId(capeId); 783 } 784 else 785 { 786 MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid()); 787 if(pMojangData) 788 { 789 // Cape 790 if(pMojangData->wchCape) 791 { 792 this->customTextureUrl2= pMojangData->wchCape; 793 } 794 else 795 { 796 if(app.DefaultCapeExists()) 797 { 798 this->customTextureUrl2= wstring(L"Special_Cape.png"); 799 } 800 else 801 { 802 this->customTextureUrl2= wstring(L""); 803 } 804 } 805 806 } 807 else 808 { 809 // if there is a custom default cloak, then set it here 810 if(app.DefaultCapeExists()) 811 { 812 this->customTextureUrl2= wstring(L"Special_Cape.png"); 813 } 814 else 815 { 816 this->customTextureUrl2 =wstring(L""); 817 } 818 } 819 } 820} 821 822DWORD Player::getCapeIdFromPath(const wstring &cape) 823{ 824 bool dlcCape = false; 825 unsigned int capeId = 0; 826 827 if(cape.size() >= 14) 828 { 829 dlcCape = cape.substr(0,3).compare(L"dlc") == 0; 830 831 wstring capeValue = cape.substr(7,cape.size()); 832 capeValue = capeValue.substr(0,capeValue.find_first_of(L'.')); 833 834 std::wstringstream ss; 835 // 4J Stu - dlc skins are numbered using decimal to make it easier for artists/people to number manually 836 // Everything else is numbered using hex 837 if(dlcCape) 838 ss << std::dec << capeValue.c_str(); 839 else 840 ss << std::hex << capeValue.c_str(); 841 ss >> capeId; 842 843 capeId = MAKE_SKIN_BITMASK(dlcCape, capeId); 844 } 845 return capeId; 846} 847 848wstring Player::getCapePathFromId(DWORD capeId) 849{ 850 // 4J Stu - This function maps the encoded DWORD we store in the player profile 851 // to a filename that is stored as a memory texture and shared between systems in game 852 wchar_t chars[256]; 853 if( GET_IS_DLC_SKIN_FROM_BITMASK(capeId) ) 854 { 855 // 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually 856 swprintf(chars,256,L"dlccape%08d.png",GET_DLC_SKIN_ID_FROM_BITMASK(capeId)); 857 858 } 859 else 860 { 861 DWORD ugcCapeIndex = GET_UGC_SKIN_ID_FROM_BITMASK(capeId); 862 DWORD defaultCapeIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(capeId); 863 if( ugcCapeIndex == 0 ) 864 { 865 swprintf(chars,256,L"defcape%08X.png",defaultCapeIndex); 866 } 867 else 868 { 869 swprintf(chars,256,L"ugccape%08X.png",ugcCapeIndex); 870 } 871 } 872 return chars; 873} 874 875void Player::ChangePlayerSkin() 876{ 877 878 if(app.vSkinNames.size()>0) 879 { 880 881 m_uiPlayerCurrentSkin++; 882 if(m_uiPlayerCurrentSkin>app.vSkinNames.size()) 883 { 884 m_uiPlayerCurrentSkin=0; 885 this->customTextureUrl=L""; 886 } 887 else 888 { 889 if(m_uiPlayerCurrentSkin>0) 890 { 891 // change this players custom texture url 892 this->customTextureUrl=app.vSkinNames[m_uiPlayerCurrentSkin-1]; 893 } 894 } 895 } 896} 897 898void Player::prepareCustomTextures() 899{ 900 MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid()); 901 902 if(pMojangData) 903 { 904 // Skin 905 if(pMojangData->wchSkin) 906 { 907 this->customTextureUrl= pMojangData->wchSkin; 908 } 909 910 // 4J Stu - Don't update the cape here, it gets set elsewhere 911 // Cape 912 //if(pMojangData->wchCape) 913 //{ 914 // this->customTextureUrl2= pMojangData->wchCape; 915 //} 916 //else 917 //{ 918 // if(app.DefaultCapeExists()) 919 // { 920 // this->customTextureUrl2= wstring(L"Default_Cape.png"); 921 // } 922 // else 923 // { 924 // this->customTextureUrl2= wstring(L""); 925 // } 926 //} 927 928 } 929 else 930 { 931 // 4J Stu - Don't update the cape here, it gets set elsewhere 932 // if there is a custom default cloak, then set it here 933 //if(app.DefaultCapeExists()) 934 //{ 935 // this->customTextureUrl2= wstring(L"Default_Cape.png"); 936 //} 937 //else 938 //{ 939 // this->customTextureUrl2 =wstring(L""); 940 //} 941 } 942 943 /*cloakTexture = wstring(L"http://s3.amazonaws.com/MinecraftCloaks/").append( name ).append( L".png" );*/ 944 //this->customTextureUrl2 = cloakTexture; 945} 946 947void Player::rideTick() 948{ 949 if (!level->isClientSide && isSneaking()) 950 { 951 ride(nullptr); 952 setSneaking(false); 953 return; 954 } 955 956 double preX = x, preY = y, preZ = z; 957 float preYRot = yRot, preXRot = xRot; 958 959 LivingEntity::rideTick(); 960 oBob = bob; 961 bob = 0; 962 963 checkRidingStatistiscs(x - preX, y - preY, z - preZ); 964 965 // riding can be set to null inside 'Entity::rideTick()'. 966 if ( riding != NULL && (riding->GetType() & eTYPE_PIG) == eTYPE_PIG ) 967 { 968 // 4J Stu - I don't know why we would want to do this, but it means that the players head is locked in position and can't move around 969 //xRot = preXRot; 970 //yRot = preYRot; 971 972 shared_ptr<Pig> pig = dynamic_pointer_cast<Pig>(riding); 973 yBodyRot = pig->yBodyRot; 974 975 while (yBodyRot - yBodyRotO < -180) 976 yBodyRotO -= 360; 977 while (yBodyRot - yBodyRotO >= 180) 978 yBodyRotO += 360; 979 } 980} 981 982 983void Player::resetPos() 984{ 985 heightOffset = 1.62f; 986 setSize(0.6f, 1.8f); 987 LivingEntity::resetPos(); 988 setHealth(getMaxHealth()); 989 deathTime = 0; 990} 991 992void Player::serverAiStep() 993{ 994 LivingEntity::serverAiStep(); 995 updateSwingTime(); 996} 997 998 999void Player::aiStep() 1000{ 1001 if (jumpTriggerTime > 0) jumpTriggerTime--; 1002 1003 if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth() && level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION)) 1004 { 1005 if (tickCount % 20 * 12 == 0) heal(1); 1006 } 1007 inventory->tick(); 1008 oBob = bob; 1009 1010 LivingEntity::aiStep(); 1011 1012 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); 1013 if (!level->isClientSide) speed->setBaseValue(abilities.getWalkingSpeed()); 1014 flyingSpeed = defaultFlySpeed; 1015 if (isSprinting()) 1016 { 1017 flyingSpeed += defaultFlySpeed * 0.3f; 1018 } 1019 1020 setSpeed((float) speed->getValue()); 1021 1022 float tBob = (float) sqrt(xd * xd + zd * zd); 1023 1024 // 4J added - we were getting a NaN with zero xd & zd 1025 if(( xd * xd + zd * zd ) < 0.00001f ) 1026 { 1027 tBob = 0.0f; 1028 } 1029 1030 float tTilt = (float) atan(-yd * 0.2f) * 15.0f; 1031 if (tBob > 0.1f) tBob = 0.1f; 1032 if (!onGround || getHealth() <= 0) tBob = 0; 1033 if (onGround || getHealth() <= 0) tTilt = 0; 1034 1035 bob += (tBob - bob) * 0.4f; 1036 1037 tilt += (tTilt - tilt) * 0.8f; 1038 1039 if (getHealth() > 0) 1040 { 1041 AABB *pickupArea = NULL; 1042 if (riding != NULL && !riding->removed) 1043 { 1044 // if the player is riding, also touch entities under the 1045 // pig/horse 1046 pickupArea = bb->minmax(riding->bb)->grow(1, 0, 1); 1047 } 1048 else 1049 { 1050 pickupArea = bb->grow(1, .5, 1); 1051 } 1052 1053 vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), pickupArea); 1054 if (entities != NULL) 1055 { 1056 AUTO_VAR(itEnd, entities->end()); 1057 for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) 1058 { 1059 shared_ptr<Entity> e = *it; //entities->at(i); 1060 if (!e->removed) 1061 { 1062 touch(e); 1063 } 1064 } 1065 } 1066 } 1067} 1068 1069 1070void Player::touch(shared_ptr<Entity> entity) 1071{ 1072 entity->playerTouch( dynamic_pointer_cast<Player>( shared_from_this() ) ); 1073} 1074 1075int Player::getScore() 1076{ 1077 return entityData->getInteger(DATA_SCORE_ID); 1078} 1079 1080void Player::setScore(int value) 1081{ 1082 entityData->set(DATA_SCORE_ID, value); 1083} 1084 1085void Player::increaseScore(int amount) 1086{ 1087 int score = getScore(); 1088 entityData->set(DATA_SCORE_ID, score + amount); 1089} 1090 1091void Player::die(DamageSource *source) 1092{ 1093 LivingEntity::die(source); 1094 setSize(0.2f, 0.2f); 1095 setPos(x, y, z); 1096 yd = 0.1f; 1097 1098 // 4J - TODO need to use a xuid 1099 if ( app.isXuidNotch( m_xuid ) ) 1100 { 1101 drop(shared_ptr<ItemInstance>( new ItemInstance(Item::apple, 1) ), true); 1102 } 1103 if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) 1104 { 1105 inventory->dropAll(); 1106 } 1107 1108 if (source != NULL) 1109 { 1110 xd = -Mth::cos((hurtDir + yRot) * PI / 180) * 0.1f; 1111 zd = -Mth::sin((hurtDir + yRot) * PI / 180) * 0.1f; 1112 } 1113 else 1114 { 1115 xd = zd = 0; 1116 } 1117 heightOffset = 0.1f; 1118} 1119 1120void Player::awardKillScore(shared_ptr<Entity> victim, int awardPoints) 1121{ 1122 increaseScore(awardPoints); 1123 vector<Objective *> *objectives = getScoreboard()->findObjectiveFor(ObjectiveCriteria::KILL_COUNT_ALL); 1124 1125 //if (victim instanceof Player) 1126 //{ 1127 // awardStat(Stats::playerKills, 1); 1128 // objectives.addAll(getScoreboard().findObjectiveFor(ObjectiveCriteria::KILL_COUNT_PLAYERS)); 1129 //} 1130 //else 1131 //{ 1132 // awardStat(Stats::mobKills, 1); 1133 //} 1134 1135 if(objectives) 1136 { 1137 for (AUTO_VAR(it,objectives->begin()); it != objectives->end(); ++it) 1138 { 1139 Objective *objective = *it; 1140 Score *score = getScoreboard()->getPlayerScore(getAName(), objective); 1141 score->increment(); 1142 } 1143 } 1144} 1145 1146bool Player::isShootable() 1147{ 1148 return true; 1149} 1150 1151bool Player::isCreativeModeAllowed() 1152{ 1153 return true; 1154} 1155 1156shared_ptr<ItemEntity> Player::drop(bool all) 1157{ 1158 return drop(inventory->removeItem(inventory->selected, all && inventory->getSelected() != NULL ? inventory->getSelected()->count : 1), false); 1159} 1160 1161shared_ptr<ItemEntity> Player::drop(shared_ptr<ItemInstance> item) 1162{ 1163 return drop(item, false); 1164} 1165 1166shared_ptr<ItemEntity> Player::drop(shared_ptr<ItemInstance> item, bool randomly) 1167{ 1168 if (item == NULL) return nullptr; 1169 if (item->count == 0) return nullptr; 1170 1171 shared_ptr<ItemEntity> thrownItem = shared_ptr<ItemEntity>( new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, item) ); 1172 thrownItem->throwTime = 20 * 2; 1173 1174 thrownItem->setThrower(getName()); 1175 1176 float pow = 0.1f; 1177 if (randomly) 1178 { 1179 float _pow = random->nextFloat() * 0.5f; 1180 float dir = random->nextFloat() * PI * 2; 1181 thrownItem->xd = -sin(dir) * _pow; 1182 thrownItem->zd = cos(dir) * _pow; 1183 thrownItem->yd = 0.2f; 1184 1185 } 1186 else 1187 { 1188 pow = 0.3f; 1189 thrownItem->xd = -sin(yRot / 180 * PI) * cos(xRot / 180 * PI) * pow; 1190 thrownItem->zd = cos(yRot / 180 * PI) * cos(xRot / 180 * PI) * pow; 1191 thrownItem->yd = -sin(xRot / 180 * PI) * pow + 0.1f; 1192 pow = 0.02f; 1193 1194 float dir = random->nextFloat() * PI * 2; 1195 pow *= random->nextFloat(); 1196 thrownItem->xd += cos(dir) * pow; 1197 thrownItem->yd += (random->nextFloat() - random->nextFloat()) * 0.1f; 1198 thrownItem->zd += sin(dir) * pow; 1199 } 1200 1201 reallyDrop(thrownItem); 1202 1203 return thrownItem; 1204} 1205 1206 1207void Player::reallyDrop(shared_ptr<ItemEntity> thrownItem) 1208{ 1209 level->addEntity(thrownItem); 1210} 1211 1212 1213float Player::getDestroySpeed(Tile *tile, bool hasProperTool) 1214{ 1215 float speed = inventory->getDestroySpeed(tile); 1216 1217 if (speed > 1) 1218 { 1219 int efficiency = EnchantmentHelper::getDiggingBonus(dynamic_pointer_cast<LivingEntity>(shared_from_this())); 1220 shared_ptr<ItemInstance> item = inventory->getSelected(); 1221 1222 if (efficiency > 0 && item != NULL) 1223 { 1224 float boost = efficiency * efficiency + 1; 1225 1226 if (item->canDestroySpecial(tile) || speed > 1) 1227 { 1228 speed += boost; 1229 } 1230 else 1231 { 1232 speed += boost * 0.08f; 1233 } 1234 } 1235 } 1236 1237 if (hasEffect(MobEffect::digSpeed)) 1238 { 1239 speed *= 1.0f + (getEffect(MobEffect::digSpeed)->getAmplifier() + 1) * .2f; 1240 } 1241 if (hasEffect(MobEffect::digSlowdown)) 1242 { 1243 speed *= 1.0f - (getEffect(MobEffect::digSlowdown)->getAmplifier() + 1) * .2f; 1244 } 1245 1246 if (isUnderLiquid(Material::water) && !EnchantmentHelper::hasWaterWorkerBonus(dynamic_pointer_cast<LivingEntity>(shared_from_this()))) speed /= 5; 1247 1248 // 4J Stu - onGround is set to true on the client when we are flying, which means 1249 // the dig speed is out of sync with the server. Removing this speed change when 1250 // flying so that we always dig as the same speed 1251 //if (!onGround) speed /= 5; 1252 1253 return speed; 1254} 1255 1256bool Player::canDestroy(Tile *tile) 1257{ 1258 return inventory->canDestroy(tile); 1259} 1260 1261void Player::readAdditionalSaveData(CompoundTag *entityTag) 1262{ 1263 LivingEntity::readAdditionalSaveData(entityTag); 1264 ListTag<CompoundTag> *inventoryList = (ListTag<CompoundTag> *) entityTag->getList(L"Inventory"); 1265 inventory->load(inventoryList); 1266 inventory->selected = entityTag->getInt(L"SelectedItemSlot"); 1267 m_isSleeping = entityTag->getBoolean(L"Sleeping"); 1268 sleepCounter = entityTag->getShort(L"SleepTimer"); 1269 1270 experienceProgress = entityTag->getFloat(L"XpP"); 1271 experienceLevel = entityTag->getInt(L"XpLevel"); 1272 totalExperience = entityTag->getInt(L"XpTotal"); 1273 setScore(entityTag->getInt(L"Score")); 1274 1275 if (m_isSleeping) 1276 { 1277 bedPosition = new Pos( Mth::floor(x), Mth::floor(y), Mth::floor(z)); 1278 stopSleepInBed(true, true, false); 1279 } 1280 1281 if (entityTag->contains(L"SpawnX") && entityTag->contains(L"SpawnY") && entityTag->contains(L"SpawnZ")) 1282 { 1283 respawnPosition = new Pos(entityTag->getInt(L"SpawnX"), entityTag->getInt(L"SpawnY"), entityTag->getInt(L"SpawnZ")); 1284 respawnForced = entityTag->getBoolean(L"SpawnForced"); 1285 } 1286 1287 foodData.readAdditionalSaveData(entityTag); 1288 abilities.loadSaveData(entityTag); 1289 1290 if (entityTag->contains(L"EnderItems")) 1291 { 1292 ListTag<CompoundTag> *enderItemsList = (ListTag<CompoundTag> *) entityTag->getList(L"EnderItems"); 1293 enderChestInventory->setItemsByTag(enderItemsList); 1294 } 1295 1296 // 4J Added 1297 m_uiGamePrivileges = entityTag->getInt(L"GamePrivileges"); 1298} 1299 1300void Player::addAdditonalSaveData(CompoundTag *entityTag) 1301{ 1302 LivingEntity::addAdditonalSaveData(entityTag); 1303 entityTag->put(L"Inventory", inventory->save(new ListTag<CompoundTag>())); 1304 entityTag->putInt(L"SelectedItemSlot", inventory->selected); 1305 entityTag->putBoolean(L"Sleeping", m_isSleeping); 1306 entityTag->putShort(L"SleepTimer", (short) sleepCounter); 1307 1308 entityTag->putFloat(L"XpP", experienceProgress); 1309 entityTag->putInt(L"XpLevel", experienceLevel); 1310 entityTag->putInt(L"XpTotal", totalExperience); 1311 entityTag->putInt(L"Score", getScore()); 1312 1313 if (respawnPosition != NULL) 1314 { 1315 entityTag->putInt(L"SpawnX", respawnPosition->x); 1316 entityTag->putInt(L"SpawnY", respawnPosition->y); 1317 entityTag->putInt(L"SpawnZ", respawnPosition->z); 1318 entityTag->putBoolean(L"SpawnForced", respawnForced); 1319 } 1320 1321 foodData.addAdditonalSaveData(entityTag); 1322 abilities.addSaveData(entityTag); 1323 1324 entityTag->put(L"EnderItems", enderChestInventory->createTag()); 1325 1326 // 4J Added 1327 entityTag->putInt(L"GamePrivileges",m_uiGamePrivileges); 1328 1329} 1330 1331bool Player::openContainer(shared_ptr<Container> container) 1332{ 1333 return true; 1334} 1335 1336bool Player::openHopper(shared_ptr<HopperTileEntity> container) 1337{ 1338 return true; 1339} 1340 1341bool Player::openHopper(shared_ptr<MinecartHopper> container) 1342{ 1343 return true; 1344} 1345 1346bool Player::openHorseInventory(shared_ptr<EntityHorse> horse, shared_ptr<Container> container) 1347{ 1348 return true; 1349} 1350 1351bool Player::startEnchanting(int x, int y, int z, const wstring &name) 1352{ 1353 return true; 1354} 1355 1356bool Player::startRepairing(int x, int y, int z) 1357{ 1358 return true; 1359} 1360 1361bool Player::startCrafting(int x, int y, int z) 1362{ 1363 return true; 1364} 1365 1366bool Player::openFireworks(int x, int y, int z) 1367{ 1368 return true; 1369} 1370 1371float Player::getHeadHeight() 1372{ 1373 return 0.12f; 1374} 1375 1376 1377void Player::setDefaultHeadHeight() 1378{ 1379 heightOffset = 1.62f; 1380} 1381 1382bool Player::hurt(DamageSource *source, float dmg) 1383{ 1384 if (isInvulnerable()) return false; 1385 if ( hasInvulnerablePrivilege() || (abilities.invulnerable && !source->isBypassInvul()) ) return false; 1386 1387 // 4J-JEV: Fix for PSVita: #3987 - [IN GAME] The user can take damage/die, when attempting to re-enter fly mode when falling from a height. 1388 if ( source == DamageSource::fall && isAllowedToFly() && abilities.flying ) return false; 1389 1390 noActionTime = 0; 1391 if (getHealth() <= 0) return false; 1392 1393 if (isSleeping() && !level->isClientSide) 1394 { 1395 stopSleepInBed(true, true, false); 1396 } 1397 1398 if ( source->scalesWithDifficulty() ) 1399 { 1400 if (level->difficulty == Difficulty::PEACEFUL) dmg = 0; 1401 if (level->difficulty == Difficulty::EASY) dmg = dmg / 2 + 1; 1402 if (level->difficulty == Difficulty::HARD) dmg = dmg * 3 / 2; 1403 } 1404 1405 if (dmg == 0) return false; 1406 1407 shared_ptr<Entity> attacker = source->getEntity(); 1408 if ( attacker != NULL && attacker->instanceof(eTYPE_ARROW) ) 1409 { 1410 shared_ptr<Arrow> arrow = dynamic_pointer_cast<Arrow>(attacker); 1411 if ( arrow->owner != NULL) 1412 { 1413 attacker = arrow->owner; 1414 } 1415 } 1416 1417 return LivingEntity::hurt(source, dmg); 1418} 1419 1420bool Player::canHarmPlayer(shared_ptr<Player> target) 1421{ 1422 Team *team = getTeam(); 1423 Team *otherTeam = target->getTeam(); 1424 1425 if (team == NULL) 1426 { 1427 return true; 1428 } 1429 if (!team->isAlliedTo(otherTeam)) 1430 { 1431 return true; 1432 } 1433 return team->isAllowFriendlyFire(); 1434} 1435 1436bool Player::canHarmPlayer(wstring targetName) 1437{ 1438 return true; 1439} 1440 1441void Player::hurtArmor(float damage) 1442{ 1443 inventory->hurtArmor(damage); 1444} 1445 1446int Player::getArmorValue() 1447{ 1448 return inventory->getArmorValue(); 1449} 1450 1451float Player::getArmorCoverPercentage() 1452{ 1453 int count = 0; 1454 for (int i = 0; i < inventory->armor.length; i++) 1455 { 1456 if (inventory->armor[i] != NULL) { 1457 count++; 1458 } 1459 } 1460 return (float) count / (float) inventory->armor.length; 1461} 1462 1463void Player::actuallyHurt(DamageSource *source, float dmg) 1464{ 1465 if (isInvulnerable()) return; 1466 if (!source->isBypassArmor() && isBlocking() && dmg > 0) 1467 { 1468 dmg = (1 + dmg) * .5f; 1469 } 1470 dmg = getDamageAfterArmorAbsorb(source, dmg); 1471 dmg = getDamageAfterMagicAbsorb(source, dmg); 1472 1473 float originalDamage = dmg; 1474 dmg = max(dmg - getAbsorptionAmount(), 0.0f); 1475 setAbsorptionAmount(getAbsorptionAmount() - (originalDamage - dmg)); 1476 if (dmg == 0) return; 1477 1478 causeFoodExhaustion(source->getFoodExhaustion()); 1479 float oldHealth = getHealth(); 1480 setHealth(getHealth() - dmg); 1481 getCombatTracker()->recordDamage(source, oldHealth, dmg); 1482} 1483 1484bool Player::openFurnace(shared_ptr<FurnaceTileEntity> container) 1485{ 1486 return true; 1487} 1488 1489bool Player::openTrap(shared_ptr<DispenserTileEntity> container) 1490{ 1491 return true; 1492} 1493 1494void Player::openTextEdit(shared_ptr<TileEntity> sign) 1495{ 1496} 1497 1498bool Player::openBrewingStand(shared_ptr<BrewingStandTileEntity> brewingStand) 1499{ 1500 return true; 1501} 1502 1503bool Player::openBeacon(shared_ptr<BeaconTileEntity> beacon) 1504{ 1505 return true; 1506} 1507 1508bool Player::openTrading(shared_ptr<Merchant> traderTarget, const wstring &name) 1509{ 1510 return true; 1511} 1512 1513/** 1514* Opens an iteminstance-dependent user interface. 1515* 1516* @param itemInstance 1517*/ 1518void Player::openItemInstanceGui(shared_ptr<ItemInstance> itemInstance) 1519{ 1520} 1521 1522bool Player::interact(shared_ptr<Entity> entity) 1523{ 1524 shared_ptr<Player> thisPlayer = dynamic_pointer_cast<Player>(shared_from_this()); 1525 1526 shared_ptr<ItemInstance> item = getSelectedItem(); 1527 shared_ptr<ItemInstance> itemClone = (item != NULL) ? item->copy() : nullptr; 1528 if ( entity->interact(thisPlayer) ) 1529 { 1530 // [EB]: Added rude check to see if we're still talking about the 1531 // same item; this code caused bucket->milkbucket to be deleted because 1532 // the milkbuckets' stack got decremented to 0. 1533 if (item != NULL && item == getSelectedItem()) 1534 { 1535 if (item->count <= 0 && !abilities.instabuild) 1536 { 1537 removeSelectedItem(); 1538 } 1539 else if (item->count < itemClone->count && abilities.instabuild) 1540 { 1541 item->count = itemClone->count; 1542 } 1543 } 1544 return true; 1545 } 1546 1547 if ( (item != NULL) && entity->instanceof(eTYPE_LIVINGENTITY) ) 1548 { 1549 // 4J - PC Comments 1550 // Hack to prevent item stacks from decrementing if the player has 1551 // the ability to instabuild 1552 if(this->abilities.instabuild) item = itemClone; 1553 if(item->interactEnemy(thisPlayer, dynamic_pointer_cast<LivingEntity>(entity))) 1554 { 1555 // 4J - PC Comments 1556 // Don't remove the item in hand if the player has the ability 1557 // to instabuild 1558 if ( (item->count <= 0) && !abilities.instabuild) 1559 { 1560 removeSelectedItem(); 1561 } 1562 return true; 1563 } 1564 } 1565 return false; 1566} 1567 1568shared_ptr<ItemInstance> Player::getSelectedItem() 1569{ 1570 return inventory->getSelected(); 1571} 1572 1573void Player::removeSelectedItem() 1574{ 1575 inventory->setItem(inventory->selected, nullptr); 1576} 1577 1578double Player::getRidingHeight() 1579{ 1580 return heightOffset - 0.5f; 1581} 1582 1583void Player::attack(shared_ptr<Entity> entity) 1584{ 1585 if (!entity->isAttackable()) 1586 { 1587 return; 1588 } 1589 1590 if (entity->skipAttackInteraction(shared_from_this())) 1591 { 1592 return; 1593 } 1594 1595 float dmg = (float) getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->getValue(); 1596 1597 int knockback = 0; 1598 float magicBoost = 0; 1599 1600 if ( entity->instanceof(eTYPE_LIVINGENTITY) ) 1601 { 1602 shared_ptr<Player> thisPlayer = dynamic_pointer_cast<Player>(shared_from_this()); 1603 shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(entity); 1604 magicBoost = EnchantmentHelper::getDamageBonus(thisPlayer, mob); 1605 knockback += EnchantmentHelper::getKnockbackBonus(thisPlayer, mob); 1606 } 1607 if (isSprinting()) 1608 { 1609 knockback += 1; 1610 } 1611 1612 if (dmg > 0 || magicBoost > 0) 1613 { 1614 bool bCrit = fallDistance > 0 && !onGround && !onLadder() && !isInWater() && !hasEffect(MobEffect::blindness) && (riding == NULL) && entity->instanceof(eTYPE_LIVINGENTITY); 1615 if (bCrit && dmg > 0) 1616 { 1617 dmg *= 1.5f; 1618 } 1619 dmg += magicBoost; 1620 1621 // Ensure we put the entity on fire if we're hitting with a 1622 // fire-enchanted weapon 1623 bool setOnFireTemporatily = false; 1624 int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast<LivingEntity>(shared_from_this())); 1625 if ( entity->instanceof(eTYPE_MOB) && fireAspect > 0 && !entity->isOnFire()) 1626 { 1627 setOnFireTemporatily = true; 1628 entity->setOnFire(1); 1629 } 1630 1631 DamageSource *damageSource = DamageSource::playerAttack(dynamic_pointer_cast<Player>(shared_from_this())); 1632 bool wasHurt = entity->hurt(damageSource, dmg); 1633 delete damageSource; 1634 if (wasHurt) 1635 { 1636 if (knockback > 0) 1637 { 1638 entity->push(-Mth::sin(yRot * PI / 180) * knockback * .5f, 0.1, Mth::cos(yRot * PI / 180) * knockback * .5f); 1639 xd *= 0.6; 1640 zd *= 0.6; 1641 setSprinting(false); 1642 } 1643 1644 if (bCrit) 1645 { 1646 crit(entity); 1647 } 1648 if (magicBoost > 0) 1649 { 1650 magicCrit(entity); 1651 } 1652 1653 if (dmg >= 18) 1654 { 1655 awardStat(GenericStats::overkill(),GenericStats::param_overkill(dmg)); 1656 } 1657 setLastHurtMob(entity); 1658 1659 1660 if ( entity->instanceof(eTYPE_LIVINGENTITY) ) 1661 { 1662 shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(entity); 1663 ThornsEnchantment::doThornsAfterAttack(shared_from_this(), mob, random); 1664 } 1665 } 1666 1667 shared_ptr<ItemInstance> item = getSelectedItem(); 1668 shared_ptr<Entity> hurtTarget = entity; 1669 if ( entity->instanceof(eTYPE_MULTIENTITY_MOB_PART) ) 1670 { 1671 shared_ptr<Entity> multiMob = dynamic_pointer_cast<Entity>((dynamic_pointer_cast<MultiEntityMobPart>(entity))->parentMob.lock()); 1672 if ( (multiMob != NULL) && multiMob->instanceof(eTYPE_LIVINGENTITY) ) 1673 { 1674 hurtTarget = dynamic_pointer_cast<LivingEntity>( multiMob ); 1675 } 1676 } 1677 if ( (item != NULL) && hurtTarget->instanceof(eTYPE_LIVINGENTITY) ) 1678 { 1679 item->hurtEnemy(dynamic_pointer_cast<LivingEntity>(hurtTarget), dynamic_pointer_cast<Player>( shared_from_this() ) ); 1680 if (item->count <= 0) 1681 { 1682 removeSelectedItem(); 1683 } 1684 } 1685 if ( entity->instanceof(eTYPE_LIVINGENTITY) ) 1686 { 1687 //awardStat(Stats.damageDealt, (int) Math.round(dmg * 10)); 1688 1689 if (fireAspect > 0 && wasHurt) 1690 { 1691 entity->setOnFire(fireAspect * 4); 1692 } 1693 else if (setOnFireTemporatily) 1694 { 1695 entity->clearFire(); 1696 } 1697 } 1698 1699 causeFoodExhaustion(FoodConstants::EXHAUSTION_ATTACK); 1700 } 1701 1702 // if (SharedConstants::INGAME_DEBUG_OUTPUT) 1703 // { 1704 // //sendMessage(ChatMessageComponent.forPlainText("DMG " + dmg + ", " + magicBoost + ", " + knockback)); 1705 // } 1706} 1707 1708void Player::crit(shared_ptr<Entity> entity) 1709{ 1710} 1711 1712void Player::magicCrit(shared_ptr<Entity> entity) 1713{ 1714} 1715 1716void Player::respawn() 1717{ 1718 deathFadeCounter=0; 1719} 1720 1721 1722void Player::animateRespawn(shared_ptr<Player> player, Level *level) 1723{ 1724 1725 for (int i = 0; i < 45; i++) 1726 { 1727 float angle = i * PI * 4.0f / 25.0f; 1728 float xo = Mth::cos(angle) * 0.7f; 1729 float zo = Mth::sin(angle) * 0.7f; 1730 1731 level->addParticle(eParticleType_netherportal, player->x + xo, player->y - player->heightOffset + 1.62f - i * .05f, player->z + zo, 0, 0, 0); 1732 } 1733 1734} 1735 1736Slot *Player::getInventorySlot(int slotId) 1737{ 1738 return NULL; 1739} 1740 1741void Player::remove() 1742{ 1743 LivingEntity::remove(); 1744 inventoryMenu->removed( dynamic_pointer_cast<Player>( shared_from_this() ) ); 1745 if (containerMenu != NULL) 1746 { 1747 containerMenu->removed( dynamic_pointer_cast<Player>( shared_from_this() ) ); 1748 } 1749} 1750 1751bool Player::isInWall() 1752{ 1753 return !m_isSleeping && LivingEntity::isInWall(); 1754} 1755 1756bool Player::isLocalPlayer() 1757{ 1758 return false; 1759} 1760 1761Player::BedSleepingResult Player::startSleepInBed(int x, int y, int z, bool bTestUse) 1762{ 1763 if (!level->isClientSide || bTestUse) 1764 { 1765 if (isSleeping() || !isAlive()) 1766 { 1767 return OTHER_PROBLEM; 1768 } 1769 1770 if (!level->dimension->isNaturalDimension()) 1771 { 1772 // may not sleep in this dimension 1773 return NOT_POSSIBLE_HERE; 1774 } 1775 1776 // 4J-PB - I'm going to move the position of these tests below 1777 // The distance check should be before the day check, otherwise you can use the bed in daytime from far away 1778 // and you'll get the message about only sleeping at night 1779 1780 if (abs(this->x - x) > 3 || abs(this->y - y) > 2 || abs(this->z - z) > 3) 1781 { 1782 // too far away 1783 return TOO_FAR_AWAY; 1784 } 1785 1786 if (!bTestUse) 1787 { 1788 // 4J-PB - We still want the tooltip for Sleep 1789 1790 double hRange = 8; 1791 double vRange = 5; 1792 vector<shared_ptr<Entity> > *monsters = level->getEntitiesOfClass(typeid(Monster), AABB::newTemp(x - hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange)); 1793 if (!monsters->empty()) 1794 { 1795 delete monsters; 1796 return NOT_SAFE; 1797 } 1798 delete monsters; 1799 } 1800 1801 // This causes a message to be displayed, so we do want to show the tooltip in test mode 1802 if (!bTestUse && level->isDay()) 1803 { 1804 // may not sleep during day 1805 return NOT_POSSIBLE_NOW; 1806 } 1807 } 1808 1809 if(bTestUse) 1810 { 1811 // 4J-PB - we're just testing use, and we get here, then the bed can be used 1812 return OK; 1813 } 1814 1815 if (isRiding()) 1816 { 1817 ride(nullptr); 1818 } 1819 1820 setSize(0.2f, 0.2f); 1821 heightOffset = .2f; 1822 if (level->hasChunkAt(x, y, z)) 1823 { 1824 1825 1826 int data = level->getData(x, y, z); 1827 int direction = BedTile::getDirection(data); 1828 float xo = .5f, zo = .5f; 1829 1830 switch (direction) 1831 { 1832 case Direction::SOUTH: 1833 zo = .9f; 1834 break; 1835 case Direction::NORTH: 1836 zo = .1f; 1837 break; 1838 case Direction::WEST: 1839 xo = .1f; 1840 break; 1841 case Direction::EAST: 1842 xo = .9f; 1843 break; 1844 } 1845 setBedOffset(direction); 1846 setPos(x + xo, y + 15.0f / 16.0f, z + zo); 1847 } 1848 else 1849 { 1850 setPos(x + .5f, y + 15.0f / 16.0f, z + .5f); 1851 } 1852 m_isSleeping = true; 1853 sleepCounter = 0; 1854 bedPosition = new Pos(x, y, z); 1855 xd = zd = yd = 0; 1856 1857 if (!level->isClientSide) 1858 { 1859 level->updateSleepingPlayerList(); 1860 } 1861 1862 return OK; 1863} 1864 1865 1866void Player::setBedOffset(int bedDirection) 1867{ 1868 // place position on pillow and feet at bottom 1869 bedOffsetX = 0; 1870 bedOffsetZ = 0; 1871 1872 switch (bedDirection) 1873 { 1874 case Direction::SOUTH: 1875 bedOffsetZ = -1.8f; 1876 break; 1877 case Direction::NORTH: 1878 bedOffsetZ = 1.8f; 1879 break; 1880 case Direction::WEST: 1881 bedOffsetX = 1.8f; 1882 break; 1883 case Direction::EAST: 1884 bedOffsetX = -1.8f; 1885 break; 1886 } 1887} 1888 1889 1890/** 1891* 1892* @param forcefulWakeUp 1893* If the player has been forced to wake up. When this happens, 1894* the client will skip the wake-up animation. For example, when 1895* the player is hurt or the bed is destroyed. 1896* @param updateLevelList 1897* If the level's sleeping player list needs to be updated. This 1898* is usually the case. 1899* @param saveRespawnPoint 1900* TODO 1901*/ 1902void Player::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint) 1903{ 1904 1905 setSize(0.6f, 1.8f); 1906 setDefaultHeadHeight(); 1907 1908 Pos *pos = bedPosition; 1909 Pos *standUp = bedPosition; 1910 if (pos != NULL && level->getTile(pos->x, pos->y, pos->z) == Tile::bed_Id) 1911 { 1912 BedTile::setOccupied(level, pos->x, pos->y, pos->z, false); 1913 1914 standUp = BedTile::findStandUpPosition(level, pos->x, pos->y, pos->z, 0); 1915 if (standUp == NULL) 1916 { 1917 standUp = new Pos(pos->x, pos->y + 1, pos->z); 1918 } 1919 setPos(standUp->x + .5f, standUp->y + heightOffset + .1f, standUp->z + .5f); 1920 } 1921 1922 m_isSleeping = false; 1923 if (!level->isClientSide && updateLevelList) 1924 { 1925 level->updateSleepingPlayerList(); 1926 } 1927 if (forcefulWakeUp) 1928 { 1929 sleepCounter = 0; 1930 } 1931 else 1932 { 1933 sleepCounter = SLEEP_DURATION; 1934 } 1935 if (saveRespawnPoint) 1936 { 1937 setRespawnPosition(bedPosition, false); 1938 } 1939} 1940 1941 1942bool Player::checkBed() 1943{ 1944 return (level->getTile(bedPosition->x, bedPosition->y, bedPosition->z) == Tile::bed_Id); 1945} 1946 1947 1948Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos, bool forced) 1949{ 1950 // make sure the chunks around the bed exist 1951 ChunkSource *chunkSource = level->getChunkSource(); 1952 chunkSource->create((pos->x - 3) >> 4, (pos->z - 3) >> 4); 1953 chunkSource->create((pos->x + 3) >> 4, (pos->z - 3) >> 4); 1954 chunkSource->create((pos->x - 3) >> 4, (pos->z + 3) >> 4); 1955 chunkSource->create((pos->x + 3) >> 4, (pos->z + 3) >> 4); 1956 1957 // make sure the bed is still standing 1958 if (level->getTile(pos->x, pos->y, pos->z) != Tile::bed_Id) 1959 { 1960 Material *bottomMaterial = level->getMaterial(pos->x, pos->y, pos->z); 1961 Material *topMaterial = level->getMaterial(pos->x, pos->y + 1, pos->z); 1962 bool freeFeet = !bottomMaterial->isSolid() && !bottomMaterial->isLiquid(); 1963 bool freeHead = !topMaterial->isSolid() && !topMaterial->isLiquid(); 1964 1965 if (forced && freeFeet && freeHead) 1966 { 1967 return pos; 1968 } 1969 return NULL; 1970 } 1971 // make sure the bed still has a stand-up position 1972 Pos *standUp = BedTile::findStandUpPosition(level, pos->x, pos->y, pos->z, 0); 1973 return standUp; 1974} 1975 1976float Player::getSleepRotation() 1977{ 1978 if (bedPosition != NULL) 1979 { 1980 int data = level->getData(bedPosition->x, bedPosition->y, bedPosition->z); 1981 int direction = BedTile::getDirection(data); 1982 1983 switch (direction) 1984 { 1985 case Direction::SOUTH: 1986 return 90; 1987 case Direction::WEST: 1988 return 0; 1989 case Direction::NORTH: 1990 return 270; 1991 case Direction::EAST: 1992 return 180; 1993 } 1994 } 1995 return 0; 1996} 1997 1998bool Player::isSleeping() 1999{ 2000 return m_isSleeping; 2001} 2002 2003bool Player::isSleepingLongEnough() 2004{ 2005 return m_isSleeping && sleepCounter >= SLEEP_DURATION; 2006} 2007 2008int Player::getSleepTimer() 2009{ 2010 return sleepCounter; 2011} 2012 2013// 4J-PB - added for death fade 2014int Player::getDeathFadeTimer() 2015{ 2016 return deathFadeCounter; 2017} 2018 2019bool Player::getPlayerFlag(int flag) 2020{ 2021 return (entityData->getByte(DATA_PLAYER_FLAGS_ID) & (1 << flag)) != 0; 2022} 2023 2024void Player::setPlayerFlag(int flag, bool value) 2025{ 2026 byte currentValue = entityData->getByte(DATA_PLAYER_FLAGS_ID); 2027 if (value) 2028 { 2029 entityData->set(DATA_PLAYER_FLAGS_ID, (byte) (currentValue | (1 << flag))); 2030 } 2031 else 2032 { 2033 entityData->set(DATA_PLAYER_FLAGS_ID, (byte) (currentValue & ~(1 << flag))); 2034 } 2035} 2036 2037 2038/** 2039* This method is currently only relevant to client-side players. It will 2040* try to load the messageId from the language file and display it to the 2041* client. 2042*/ 2043void Player::displayClientMessage(int messageId) 2044{ 2045 2046} 2047 2048Pos *Player::getRespawnPosition() 2049{ 2050 return respawnPosition; 2051} 2052 2053bool Player::isRespawnForced() 2054{ 2055 return respawnForced; 2056} 2057 2058void Player::setRespawnPosition(Pos *respawnPosition, bool forced) 2059{ 2060 if (respawnPosition != NULL) 2061 { 2062 this->respawnPosition = new Pos(*respawnPosition); 2063 respawnForced = forced; 2064 } 2065 else 2066 { 2067 this->respawnPosition = NULL; 2068 respawnForced = false; 2069 } 2070} 2071 2072void Player::awardStat(Stat *stat, byteArray paramBlob) 2073{ 2074 if (paramBlob.data != NULL) 2075 { 2076 delete [] paramBlob.data; 2077 } 2078} 2079 2080 2081void Player::jumpFromGround() 2082{ 2083 LivingEntity::jumpFromGround(); 2084 2085 // 4J Stu - This seems to have been missed from 1.7.3, but do we care? 2086 //awardStat(Stats::jump, 1); 2087 2088 if (isSprinting()) 2089 { 2090 causeFoodExhaustion(FoodConstants::EXHAUSTION_SPRINT_JUMP); 2091 } 2092 else 2093 { 2094 causeFoodExhaustion(FoodConstants::EXHAUSTION_JUMP); 2095 } 2096} 2097 2098 2099void Player::travel(float xa, float ya) 2100{ 2101 double preX = x, preY = y, preZ = z; 2102 2103 if (abilities.flying && riding == NULL) 2104 { 2105 double ydo = yd; 2106 float ofs = flyingSpeed; 2107 flyingSpeed = abilities.getFlyingSpeed(); 2108 LivingEntity::travel(xa, ya); 2109 yd = ydo * 0.6; 2110 flyingSpeed = ofs; 2111 } 2112 else 2113 { 2114 LivingEntity::travel(xa, ya); 2115 } 2116 2117 checkMovementStatistiscs(x - preX, y - preY, z - preZ); 2118} 2119 2120float Player::getSpeed() 2121{ 2122 return (float) getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue(); 2123} 2124 2125void Player::checkMovementStatistiscs(double dx, double dy, double dz) 2126{ 2127 2128 if (riding != NULL) 2129 { 2130 return; 2131 } 2132 if (isUnderLiquid(Material::water)) 2133 { 2134 int distance = (int) Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f); 2135 if (distance > 0) 2136 { 2137 //awardStat(Stats::diveOneCm, distance); 2138 causeFoodExhaustion(FoodConstants::EXHAUSTION_SWIM * distance * .01f); 2139 } 2140 } 2141 else if (isInWater()) 2142 { 2143 int horizontalDistance = (int) Math::round(sqrt(dx * dx + dz * dz) * 100.0f); 2144 if (horizontalDistance > 0) 2145 { 2146 distanceSwim += horizontalDistance; 2147 if( distanceSwim >= 100 ) 2148 { 2149 int newDistance = distanceSwim - (distanceSwim % 100); 2150 distanceSwim -= newDistance; 2151 awardStat( GenericStats::swimOneM(), GenericStats::param_swim(newDistance/100) ); 2152 } 2153 causeFoodExhaustion(FoodConstants::EXHAUSTION_SWIM * horizontalDistance * .01f); 2154 } 2155 } 2156 else if (onLadder()) 2157 { 2158 if (dy > 0) 2159 { 2160 distanceClimb += (int) Math::round(dy * 100.0f); 2161 if( distanceClimb >= 100 ) 2162 { 2163 int newDistance = distanceClimb - (distanceClimb % 100); 2164 distanceClimb -= newDistance; 2165 awardStat( GenericStats::climbOneM(), GenericStats::param_climb(newDistance/100) ); 2166 } 2167 } 2168 } 2169 else if (onGround) 2170 { 2171 int horizontalDistance = (int) Math::round(sqrt(dx * dx + dz * dz) * 100.0f); 2172 if (horizontalDistance > 0) 2173 { 2174 distanceWalk += horizontalDistance; 2175 if( distanceWalk >= 100 ) 2176 { 2177 int newDistance = distanceWalk - (distanceWalk % 100); 2178 distanceWalk -= newDistance; 2179 awardStat( GenericStats::walkOneM(), GenericStats::param_walk(newDistance/100) ); 2180 } 2181 if (isSprinting()) 2182 { 2183 causeFoodExhaustion(FoodConstants::EXHAUSTION_SPRINT * horizontalDistance * .01f); 2184 } 2185 else 2186 { 2187 causeFoodExhaustion(FoodConstants::EXHAUSTION_WALK * horizontalDistance * .01f); 2188 } 2189 } 2190 } 2191} 2192 2193 2194void Player::checkRidingStatistiscs(double dx, double dy, double dz) 2195{ 2196 if (riding != NULL) 2197 { 2198 int distance = (int) Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f); 2199 if (distance > 0) 2200 { 2201 if ( riding->instanceof(eTYPE_MINECART) ) 2202 { 2203 distanceMinecart += distance; 2204 if( distanceMinecart >= 100 ) 2205 { 2206 int newDistance = distanceMinecart - (distanceMinecart % 100); 2207 distanceMinecart -= newDistance; 2208 awardStat( GenericStats::minecartOneM(), GenericStats::param_minecart(newDistance/100) ); 2209 } 2210 2211 int dist = 0; 2212 if (minecartAchievementPos == NULL) 2213 { 2214 minecartAchievementPos = new Pos(Mth::floor(x), Mth::floor(y), Mth::floor(z)); 2215 } 2216 // 4J-PB - changed this because our world isn't big enough to go 1000m 2217 else 2218 { 2219 // 4-JEV, changed slightly to add extra parameters for event on durango. 2220 int dist = minecartAchievementPos->dist(Mth::floor(x), Mth::floor(y), Mth::floor(z)); 2221#ifdef _XBOX_ONE 2222 // 4J-PB - send the event to cause the progress bar to increase on XB1 2223 if (m_bAwardedOnARail==false) 2224 { 2225 if(dist < 500) 2226 { 2227 if((dist>0) && (dist%100==0)) 2228 { 2229 awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); 2230 } 2231 } 2232 else 2233 { 2234 awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); 2235 m_bAwardedOnARail=true; 2236 } 2237 } 2238#else 2239 if ((m_bAwardedOnARail==false) && (dist >= 500)) 2240 { 2241 awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); 2242 m_bAwardedOnARail=true; 2243 } 2244#endif 2245 } 2246 2247 } 2248 else if ( riding->instanceof(eTYPE_BOAT) ) 2249 { 2250 distanceBoat += distance; 2251 if( distanceBoat >= 100 ) 2252 { 2253 int newDistance = distanceBoat - (distanceBoat % 100); 2254 distanceBoat -= newDistance; 2255 awardStat(GenericStats::boatOneM(), GenericStats::param_boat(newDistance/100) ); 2256 } 2257 } 2258 else if ( riding->instanceof(eTYPE_PIG) ) 2259 { 2260 distancePig += distance; 2261 if( distancePig >= 100 ) 2262 { 2263 int newDistance = distancePig - (distancePig % 100); 2264 distancePig -= newDistance; 2265 awardStat(GenericStats::pigOneM(), GenericStats::param_pig(newDistance/100) ); 2266 } 2267 } 2268 } 2269 } 2270} 2271 2272 2273void Player::causeFallDamage(float distance) 2274{ 2275 if (abilities.mayfly) return; 2276 2277 if (distance >= 2) 2278 { 2279 distanceFall += (int) Math::round(distance * 100.0); 2280 if( distanceFall >= 100 ) 2281 { 2282 int newDistance = distanceFall - (distanceFall % 100); 2283 distanceFall -= newDistance; 2284 awardStat(GenericStats::fallOneM(), GenericStats::param_fall(newDistance/100) ); 2285 } 2286 } 2287 LivingEntity::causeFallDamage(distance); 2288} 2289 2290 2291void Player::killed(shared_ptr<LivingEntity> mob) 2292{ 2293 // 4J-PB - added the lavaslime enemy - fix for #64007 - TU7: Code: Achievements: TCR#073: Killing Magma Cubes doesn't unlock "Monster Hunter" Achievement. 2294 if( mob->instanceof(eTYPE_ENEMY) || mob->GetType() == eTYPE_GHAST || mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME || mob->GetType() == eTYPE_ENDERDRAGON) 2295 { 2296 awardStat(GenericStats::killEnemy(), GenericStats::param_noArgs()); 2297 2298 switch( mob->GetType() ) 2299 { 2300 case eTYPE_CREEPER: 2301 awardStat(GenericStats::killsCreeper(), GenericStats::param_noArgs()); 2302 break; 2303 case eTYPE_SKELETON: 2304 if( mob->isRiding() && mob->riding->GetType() == eTYPE_SPIDER ) 2305 awardStat(GenericStats::killsSpiderJockey(), GenericStats::param_noArgs()); 2306 else 2307 awardStat(GenericStats::killsSkeleton(), GenericStats::param_noArgs()); 2308 break; 2309 case eTYPE_SPIDER: 2310 if( mob->rider.lock() != NULL && mob->rider.lock()->GetType() == eTYPE_SKELETON ) 2311 awardStat(GenericStats::killsSpiderJockey(), GenericStats::param_noArgs()); 2312 else 2313 awardStat(GenericStats::killsSpider(), GenericStats::param_noArgs()); 2314 break; 2315 case eTYPE_ZOMBIE: 2316 awardStat(GenericStats::killsZombie(), GenericStats::param_noArgs()); 2317 break; 2318 case eTYPE_PIGZOMBIE: 2319 if( level->dimension->id == 0 ) 2320 awardStat(GenericStats::killsZombiePigman(), GenericStats::param_noArgs()); 2321 else 2322 awardStat(GenericStats::killsNetherZombiePigman(), GenericStats::param_noArgs()); 2323 break; 2324 case eTYPE_GHAST: 2325 awardStat(GenericStats::killsGhast(), GenericStats::param_noArgs()); 2326 break; 2327 case eTYPE_SLIME: 2328 awardStat(GenericStats::killsSlime(), GenericStats::param_noArgs()); 2329 break; 2330 case eTYPE_ENDERDRAGON: 2331 awardStat(GenericStats::killsEnderdragon(), GenericStats::param_noArgs()); 2332 break; 2333 } 2334 } 2335 else if( mob->GetType() == eTYPE_COW ) 2336 { 2337 awardStat(GenericStats::killCow(), GenericStats::param_noArgs()); 2338 } 2339} 2340 2341void Player::makeStuckInWeb() 2342{ 2343 if (!abilities.flying) LivingEntity::makeStuckInWeb(); 2344} 2345 2346Icon *Player::getItemInHandIcon(shared_ptr<ItemInstance> item, int layer) 2347{ 2348 Icon *icon = LivingEntity::getItemInHandIcon(item, layer); 2349 if (item->id == Item::fishingRod->id && fishing != NULL) 2350 { 2351 icon = Item::fishingRod->getEmptyIcon(); 2352 } 2353 else if (item->getItem()->hasMultipleSpriteLayers()) 2354 { 2355 return item->getItem()->getLayerIcon(item->getAuxValue(), layer); 2356 } 2357 else if (useItem != NULL && item->id == Item::bow_Id) 2358 { 2359 int ticksHeld = (item->getUseDuration() - useItemDuration); 2360 if (ticksHeld >= BowItem::MAX_DRAW_DURATION - 2) 2361 { 2362 return Item::bow->getDrawnIcon(2); 2363 } 2364 if (ticksHeld > (2 * BowItem::MAX_DRAW_DURATION) / 3) 2365 { 2366 return Item::bow->getDrawnIcon(1); 2367 } 2368 if (ticksHeld > 0) 2369 { 2370 return Item::bow->getDrawnIcon(0); 2371 } 2372 } 2373 return icon; 2374} 2375 2376shared_ptr<ItemInstance> Player::getArmor(int pos) 2377{ 2378 return inventory->getArmor(pos); 2379} 2380 2381void Player::increaseXp(int i) 2382{ 2383 increaseScore(i); 2384 int max = INT_MAX - totalExperience; 2385 if (i > max) 2386 { 2387 i = max; 2388 } 2389 experienceProgress += (float) i / getXpNeededForNextLevel(); 2390 totalExperience += i; 2391 while (experienceProgress >= 1) 2392 { 2393 experienceProgress = (experienceProgress - 1) * getXpNeededForNextLevel(); 2394 giveExperienceLevels(1); 2395 experienceProgress /= getXpNeededForNextLevel(); 2396 } 2397} 2398 2399void Player::giveExperienceLevels(int amount) 2400{ 2401 experienceLevel += amount; 2402 if (experienceLevel < 0) 2403 { 2404 experienceLevel = 0; 2405 experienceProgress = 0; 2406 totalExperience = 0; 2407 } 2408 2409 if (amount > 0 && experienceLevel % 5 == 0 && lastLevelUpTime < tickCount - SharedConstants::TICKS_PER_SECOND * 5.0f) 2410 { 2411 float vol = experienceLevel > 30 ? 1 : experienceLevel / 30.0f; 2412 level->playEntitySound(shared_from_this(), eSoundType_RANDOM_LEVELUP, vol * 0.75f, 1); 2413 lastLevelUpTime = tickCount; 2414 } 2415} 2416 2417int Player::getXpNeededForNextLevel() 2418{ 2419 // Update xp calculations from 1.3 2420 if (experienceLevel >= 30) 2421 { 2422 return 17 + 15 * 3 + (experienceLevel - 30) * 7; 2423 } 2424 if (experienceLevel >= 15) 2425 { 2426 return 17 + (experienceLevel - 15) * 3; 2427 } 2428 return 17; 2429} 2430 2431/** 2432* This method adds on to the player's exhaustion, which may decrease the 2433* player's food level. 2434* 2435* @param amount 2436* Amount of exhaustion to add, between 0 and 20 (setting it to 2437* 20 will guarantee that at least 1, and at most 4, food points 2438* are deducted). See FoodConstants for cost suggestions. 2439*/ 2440void Player::causeFoodExhaustion(float amount) 2441{ 2442 if( isAllowedToIgnoreExhaustion() || ( isAllowedToFly() && abilities.flying) ) return; 2443 if (abilities.invulnerable || hasInvulnerablePrivilege() ) return; 2444 2445 // 4J Stu - Added 1.8.2 bug fix (TU6) - If players cannot eat, then their food bar should not decrease due to exhaustion 2446 if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) return; 2447 2448 if (!level->isClientSide) 2449 { 2450 foodData.addExhaustion(amount); 2451 } 2452} 2453 2454FoodData *Player::getFoodData() 2455{ 2456 return &foodData; 2457} 2458 2459bool Player::canEat(bool magicalItem) 2460{ 2461 return (magicalItem || foodData.needsFood()) && !abilities.invulnerable && !hasInvulnerablePrivilege(); 2462} 2463 2464bool Player::isHurt() 2465{ 2466 return getHealth() > 0 && getHealth() < getMaxHealth(); 2467} 2468 2469void Player::startUsingItem(shared_ptr<ItemInstance> instance, int duration) 2470{ 2471 if (instance == useItem) return; 2472 useItem = instance; 2473 useItemDuration = duration; 2474 if (!level->isClientSide) 2475 { 2476 setUsingItemFlag(true); 2477 } 2478 2479 // 4J-JEV, hook for ItemUsed event, and ironbelly achievement. 2480 awardStat(GenericStats::itemsUsed(instance->getItem()->id), 2481 GenericStats::param_itemsUsed(dynamic_pointer_cast<Player>(shared_from_this()),instance)); 2482 2483#if (!defined _DURANGO) && (defined _EXTENDED_ACHIEVEMENTS) 2484 if ( (instance->getItem()->id == Item::rotten_flesh_Id) && (getFoodData()->getFoodLevel() == 0) ) 2485 awardStat(GenericStats::ironBelly(), GenericStats::param_ironBelly()); 2486#endif 2487} 2488 2489bool Player::mayDestroyBlockAt(int x, int y, int z) 2490{ 2491 if (abilities.mayBuild) 2492 { 2493 return true; 2494 } 2495 int t = level->getTile(x, y, z); 2496 if (t > 0) { 2497 Tile *tile = Tile::tiles[t]; 2498 2499 if (tile->material->isDestroyedByHand()) 2500 { 2501 return true; 2502 } 2503 else if (getSelectedItem() != NULL) 2504 { 2505 shared_ptr<ItemInstance> carried = getSelectedItem(); 2506 2507 if (carried->canDestroySpecial(tile) || carried->getDestroySpeed(tile) > 1) 2508 { 2509 return true; 2510 } 2511 } 2512 } 2513 return false; 2514} 2515 2516bool Player::mayUseItemAt(int x, int y, int z, int face, shared_ptr<ItemInstance> item) 2517{ 2518 if (abilities.mayBuild) 2519 { 2520 return true; 2521 } 2522 if (item != NULL) 2523 { 2524 return item->mayBePlacedInAdventureMode(); 2525 } 2526 return false; 2527} 2528 2529int Player::getExperienceReward(shared_ptr<Player> killedBy) 2530{ 2531 if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) return 0; 2532 int reward = experienceLevel * 7; 2533 if (reward > 100) 2534 { 2535 return 100; 2536 } 2537 return reward; 2538} 2539 2540bool Player::isAlwaysExperienceDropper() 2541{ 2542 // players always drop experience 2543 return true; 2544} 2545 2546wstring Player::getAName() 2547{ 2548 return name; 2549} 2550 2551bool Player::shouldShowName() 2552{ 2553 return true; 2554} 2555 2556void Player::restoreFrom(shared_ptr<Player> oldPlayer, bool restoreAll) 2557{ 2558 if(restoreAll) 2559 { 2560 inventory->replaceWith(oldPlayer->inventory); 2561 2562 setHealth(oldPlayer->getHealth()); 2563 foodData = oldPlayer->foodData; 2564 2565 experienceLevel = oldPlayer->experienceLevel; 2566 totalExperience = oldPlayer->totalExperience; 2567 experienceProgress = oldPlayer->experienceProgress; 2568 2569 setScore(oldPlayer->getScore()); 2570 portalEntranceDir = oldPlayer->portalEntranceDir; 2571 } 2572 else if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) 2573 { 2574 inventory->replaceWith(oldPlayer->inventory); 2575 2576 experienceLevel = oldPlayer->experienceLevel; 2577 totalExperience = oldPlayer->totalExperience; 2578 experienceProgress = oldPlayer->experienceProgress; 2579 setScore(oldPlayer->getScore()); 2580 } 2581 enderChestInventory = oldPlayer->enderChestInventory; 2582} 2583 2584bool Player::makeStepSound() 2585{ 2586 return !abilities.flying; 2587} 2588 2589void Player::onUpdateAbilities() 2590{ 2591} 2592 2593void Player::setGameMode(GameType *mode) 2594{ 2595} 2596 2597wstring Player::getName() 2598{ 2599 return name; 2600} 2601 2602wstring Player::getDisplayName() 2603{ 2604 //PlayerTeam.formatNameForTeam(getTeam(), name); 2605 2606 // If player display name is not set, return name 2607 return m_displayName.size() > 0 ? m_displayName : name; 2608} 2609 2610wstring Player::getNetworkName() 2611{ 2612 // 4J: We can only transmit gamertag in network packets 2613 return name; 2614} 2615 2616Level *Player::getCommandSenderWorld() 2617{ 2618 return level; 2619} 2620 2621shared_ptr<PlayerEnderChestContainer> Player::getEnderChestInventory() 2622{ 2623 return enderChestInventory; 2624} 2625 2626shared_ptr<ItemInstance> Player::getCarried(int slot) 2627{ 2628 if (slot == 0) return inventory->getSelected(); 2629 return inventory->armor[slot - 1]; 2630} 2631 2632shared_ptr<ItemInstance> Player::getCarriedItem() 2633{ 2634 return inventory->getSelected(); 2635} 2636 2637void Player::setEquippedSlot(int slot, shared_ptr<ItemInstance> item) 2638{ 2639 inventory->armor[slot] = item; 2640} 2641 2642bool Player::isInvisibleTo(shared_ptr<Player> player) 2643{ 2644 return isInvisible(); 2645} 2646 2647ItemInstanceArray Player::getEquipmentSlots() 2648{ 2649 return inventory->armor; 2650} 2651 2652bool Player::isCapeHidden() 2653{ 2654 return getPlayerFlag(FLAG_HIDE_CAPE); 2655} 2656 2657bool Player::isPushedByWater() 2658{ 2659 return !abilities.flying; 2660} 2661 2662Scoreboard *Player::getScoreboard() 2663{ 2664 return level->getScoreboard(); 2665} 2666 2667Team *Player::getTeam() 2668{ 2669 return getScoreboard()->getPlayersTeam(name); 2670} 2671 2672void Player::setAbsorptionAmount(float absorptionAmount) 2673{ 2674 if (absorptionAmount < 0) absorptionAmount = 0; 2675 getEntityData()->set(DATA_PLAYER_ABSORPTION_ID, absorptionAmount); 2676} 2677 2678float Player::getAbsorptionAmount() 2679{ 2680 return getEntityData()->getFloat(DATA_PLAYER_ABSORPTION_ID); 2681} 2682 2683int Player::getTexture() 2684{ 2685 switch(m_skinIndex) 2686 { 2687 case eDefaultSkins_Skin0: 2688 return TN_MOB_CHAR; // 4J - was L"/mob/char.png"; 2689 case eDefaultSkins_Skin1: 2690 return TN_MOB_CHAR1; // 4J - was L"/mob/char1.png"; 2691 case eDefaultSkins_Skin2: 2692 return TN_MOB_CHAR2; // 4J - was L"/mob/char2.png"; 2693 case eDefaultSkins_Skin3: 2694 return TN_MOB_CHAR3; // 4J - was L"/mob/char3.png"; 2695 case eDefaultSkins_Skin4: 2696 return TN_MOB_CHAR4; // 4J - was L"/mob/char4.png"; 2697 case eDefaultSkins_Skin5: 2698 return TN_MOB_CHAR5; // 4J - was L"/mob/char5.png"; 2699 case eDefaultSkins_Skin6: 2700 return TN_MOB_CHAR6; // 4J - was L"/mob/char6.png"; 2701 case eDefaultSkins_Skin7: 2702 return TN_MOB_CHAR7; // 4J - was L"/mob/char7.png"; 2703 2704 default: 2705 return TN_MOB_CHAR; // 4J - was L"/mob/char.png"; 2706 } 2707} 2708 2709int Player::hash_fnct(const shared_ptr<Player> k) 2710{ 2711 // TODO 4J Stu - Should we just be using the pointers and hashing them? 2712#ifdef __PS3__ 2713 return (int)boost::hash_value( k->name ); // 4J Stu - Names are completely unique? 2714#else 2715 return (int)std::hash<wstring>{}(k->name); // 4J Stu - Names are completely unique? 2716#endif //__PS3__ 2717} 2718 2719bool Player::eq_test(const shared_ptr<Player> x, const shared_ptr<Player> y) 2720{ 2721 // TODO 4J Stu - Should we just be using the pointers and comparing them for equality? 2722 return x->name.compare( y->name ) == 0; // 4J Stu - Names are completely unique? 2723} 2724 2725 2726unsigned int Player::getPlayerGamePrivilege(EPlayerGamePrivileges privilege) 2727{ 2728 return Player::getPlayerGamePrivilege(m_uiGamePrivileges,privilege); 2729} 2730 2731unsigned int Player::getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlayerGamePrivileges privilege) 2732{ 2733 if( privilege == ePlayerGamePrivilege_All ) 2734 { 2735 return uiGamePrivileges; 2736 } 2737 else if (privilege < ePlayerGamePrivilege_MAX ) 2738 { 2739 return uiGamePrivileges&(1<<privilege); 2740 } 2741 return 0; 2742} 2743 2744void Player::setPlayerGamePrivilege(EPlayerGamePrivileges privilege, unsigned int value) 2745{ 2746 Player::setPlayerGamePrivilege(m_uiGamePrivileges,privilege,value); 2747} 2748 2749void Player::setPlayerGamePrivilege(unsigned int &uiGamePrivileges, EPlayerGamePrivileges privilege, unsigned int value) 2750{ 2751 if( privilege == ePlayerGamePrivilege_All ) 2752 { 2753 uiGamePrivileges = value; 2754 } 2755 else if(privilege ==ePlayerGamePrivilege_HOST) 2756 { 2757 if(value == 0) 2758 { 2759 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_Op,0); 2760 } 2761 else 2762 { 2763 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_Op,1); 2764 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleInvisible,1); 2765 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleFly,1); 2766 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleClassicHunger,1); 2767 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanTeleport,1); 2768 } 2769 } 2770 else if (privilege < ePlayerGamePrivilege_MAX ) 2771 { 2772 if(value!=0) 2773 { 2774 uiGamePrivileges|=(1<<privilege); 2775 } 2776 else 2777 { 2778 // Some privileges will turn other things off as well 2779 switch(privilege) 2780 { 2781 case ePlayerGamePrivilege_CanToggleInvisible: 2782 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_Invisible,0); 2783 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_Invulnerable,0); 2784 break; 2785 case ePlayerGamePrivilege_CanToggleFly: 2786 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanFly,0); 2787 break; 2788 case ePlayerGamePrivilege_CanToggleClassicHunger: 2789 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_ClassicHunger,0); 2790 break; 2791 case ePlayerGamePrivilege_Op: 2792 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleInvisible,0); 2793 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleFly,0); 2794 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanToggleClassicHunger,0); 2795 Player::setPlayerGamePrivilege(uiGamePrivileges,ePlayerGamePrivilege_CanTeleport,0); 2796 break; 2797 } 2798 // off 2799 uiGamePrivileges&=~(1<<privilege); 2800 } 2801 } 2802} 2803 2804bool Player::isAllowedToUse(Tile *tile) 2805{ 2806 bool allowed = true; 2807 if(tile != NULL && app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) 2808 { 2809 allowed = false; 2810 2811 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches) != 0) 2812 { 2813 switch(tile->id) 2814 { 2815 case Tile::door_wood_Id: 2816 case Tile::button_stone_Id: 2817 case Tile::button_wood_Id: 2818 case Tile::lever_Id: 2819 case Tile::fenceGate_Id: 2820 case Tile::trapdoor_Id: 2821 allowed = true; 2822 break; 2823 } 2824 } 2825 2826 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) != 0) 2827 { 2828 switch(tile->id) 2829 { 2830 case Tile::chest_Id: 2831 case Tile::furnace_Id: 2832 case Tile::furnace_lit_Id: 2833 case Tile::dispenser_Id: 2834 case Tile::brewingStand_Id: 2835 case Tile::enchantTable_Id: 2836 case Tile::workBench_Id: 2837 case Tile::anvil_Id: 2838 case Tile::enderChest_Id: 2839 allowed = true; 2840 break; 2841 } 2842 } 2843 2844 if(!allowed && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) == 0) 2845 { 2846 switch(tile->id) 2847 { 2848 case Tile::door_wood_Id: 2849 case Tile::button_stone_Id: 2850 case Tile::button_wood_Id: 2851 case Tile::lever_Id: 2852 case Tile::fenceGate_Id: 2853 case Tile::trapdoor_Id: 2854 case Tile::chest_Id: 2855 case Tile::furnace_Id: 2856 case Tile::furnace_lit_Id: 2857 case Tile::dispenser_Id: 2858 case Tile::brewingStand_Id: 2859 case Tile::enchantTable_Id: 2860 case Tile::workBench_Id: 2861 case Tile::anvil_Id: 2862 case Tile::enderChest_Id: 2863 allowed = false; 2864 break; 2865 default: 2866 allowed = true; 2867 break; 2868 } 2869 } 2870 } 2871 2872 return allowed; 2873} 2874 2875bool Player::isAllowedToUse(shared_ptr<ItemInstance> item) 2876{ 2877 bool allowed = true; 2878 if(item != NULL && app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) 2879 { 2880 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) 2881 { 2882 allowed = false; 2883 } 2884 2885 // 4J Stu - TU8 Players should always be able to eat food items, even if the build option is turned of 2886 switch(item->id) 2887 { 2888 // food 2889 case Item::mushroomStew_Id: 2890 case Item::apple_Id: 2891 case Item::bread_Id: 2892 case Item::porkChop_raw_Id: 2893 case Item::porkChop_cooked_Id: 2894 case Item::apple_gold_Id: 2895 case Item::fish_raw_Id: 2896 case Item::fish_cooked_Id: 2897 case Item::cookie_Id: 2898 case Item::beef_cooked_Id: 2899 case Item::beef_raw_Id: 2900 case Item::chicken_cooked_Id: 2901 case Item::chicken_raw_Id: 2902 case Item::melon_Id: 2903 case Item::rotten_flesh_Id: 2904 // bow 2905 case Item::bow_Id: 2906 case Item::sword_diamond_Id: 2907 case Item::sword_gold_Id: 2908 case Item::sword_iron_Id: 2909 case Item::sword_stone_Id: 2910 case Item::sword_wood_Id: 2911 allowed = true; 2912 break; 2913 } 2914 } 2915 2916 return allowed; 2917} 2918 2919bool Player::isAllowedToInteract(shared_ptr<Entity> target) 2920{ 2921 bool allowed = true; 2922 if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) 2923 { 2924 if (target->instanceof(eTYPE_MINECART)) 2925 { 2926 if (getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) == 0) 2927 { 2928 shared_ptr<Minecart> minecart = dynamic_pointer_cast<Minecart>( target ); 2929 if (minecart->getType() == Minecart::TYPE_CHEST) 2930 allowed = false; 2931 } 2932 2933 } 2934 else 2935 { 2936 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) 2937 { 2938 allowed = false; 2939 } 2940 2941 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotMine) != 0) 2942 { 2943 allowed = false; 2944 } 2945 } 2946 } 2947 2948 return allowed; 2949} 2950 2951bool Player::isAllowedToMine() 2952{ 2953 bool allowed = true; 2954 if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) 2955 { 2956 if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotMine) != 0) 2957 { 2958 allowed = false; 2959 } 2960 } 2961 return allowed; 2962} 2963 2964bool Player::isAllowedToAttackPlayers() 2965{ 2966 bool allowed = true; 2967 if( hasInvisiblePrivilege() || ((app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotAttackPlayers)) ) 2968 { 2969 allowed = false; 2970 } 2971 return allowed; 2972} 2973 2974bool Player::isAllowedToAttackAnimals() 2975{ 2976 bool allowed = true; 2977 if( (app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotAttackAnimals) ) 2978 { 2979 allowed = false; 2980 } 2981 return allowed; 2982} 2983 2984bool Player::isAllowedToHurtEntity(shared_ptr<Entity> target) 2985{ 2986 bool allowed = true; 2987 2988 if(!isAllowedToMine()) 2989 { 2990 switch(target->GetType()) 2991 { 2992 case eTYPE_HANGING_ENTITY: 2993 case eTYPE_PAINTING: 2994 case eTYPE_ITEM_FRAME: 2995 2996 // 4J-JEV: Fix for #88212, 2997 // Untrusted players shouldn't be able to damage minecarts or boats. 2998 case eTYPE_BOAT: 2999 case eTYPE_MINECART: 3000 3001 allowed = false; 3002 break; 3003 }; 3004 } 3005 return allowed; 3006} 3007 3008bool Player::isAllowedToFly() 3009{ 3010 bool allowed = false; 3011 if(app.GetGameHostOption(eGameHostOption_HostCanFly) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanFly) != 0) 3012 { 3013 allowed = true; 3014 } 3015 return allowed; 3016} 3017 3018bool Player::isAllowedToIgnoreExhaustion() 3019{ 3020 bool allowed = false; 3021 if( (app.GetGameHostOption(eGameHostOption_HostCanChangeHunger) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_ClassicHunger) != 0) || 3022 (isAllowedToFly() && abilities.flying) ) 3023 { 3024 allowed = true; 3025 } 3026 return allowed; 3027} 3028 3029bool Player::isAllowedToTeleport() 3030{ 3031 bool allowed = false; 3032 if( isModerator() && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanTeleport) != 0) 3033 { 3034 allowed = true; 3035 } 3036 return allowed; 3037} 3038 3039bool Player::hasInvisiblePrivilege() 3040{ 3041 bool enabled = false; 3042 if(app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Invisible) != 0) 3043 { 3044 enabled = true; 3045 } 3046 return enabled; 3047} 3048 3049bool Player::hasInvulnerablePrivilege() 3050{ 3051 bool enabled = false; 3052 if(app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Invulnerable) != 0) 3053 { 3054 enabled = true; 3055 } 3056 return enabled; 3057} 3058 3059bool Player::isModerator() 3060{ 3061 return getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Op) != 0; 3062} 3063 3064void Player::enableAllPlayerPrivileges(unsigned int &uigamePrivileges, bool enable) 3065{ 3066 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotMine, enable?0:1); 3067 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotBuild, enable?0:1); 3068 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotAttackPlayers, enable?0:1); 3069 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotAttackAnimals, enable?0:1); 3070 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches, enable?1:0); 3071 Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CanUseContainers, enable?1:0); 3072} 3073 3074void Player::enableAllPlayerPrivileges(bool enable) 3075{ 3076 Player::enableAllPlayerPrivileges(m_uiGamePrivileges,enable); 3077} 3078 3079bool Player::canCreateParticles() 3080{ 3081 return !hasInvisiblePrivilege(); 3082} 3083 3084vector<ModelPart *> *Player::GetAdditionalModelParts() 3085{ 3086 if(m_ppAdditionalModelParts==NULL && !m_bCheckedForModelParts) 3087 { 3088 bool hasCustomTexture = !customTextureUrl.empty(); 3089 bool customTextureIsDefaultSkin = customTextureUrl.substr(0,3).compare(L"def") == 0; 3090 3091 // see if we can find the parts 3092 m_ppAdditionalModelParts=app.GetAdditionalModelParts(m_dwSkinId); 3093 3094 // If it's a default texture (which has no parts), we have the parts, or we already have the texture (in which case we should have parts if there are any) then we are done 3095 if(!hasCustomTexture || customTextureIsDefaultSkin || m_ppAdditionalModelParts != NULL || app.IsFileInMemoryTextures(customTextureUrl)) 3096 { 3097 m_bCheckedForModelParts=true; 3098 } 3099 if(m_ppAdditionalModelParts == NULL && !m_bCheckedDLCForModelParts) 3100 { 3101 m_bCheckedDLCForModelParts = true; 3102 3103 // we don't have the data from the dlc skin yet 3104 app.DebugPrintf("m_bCheckedForModelParts Couldn't get model parts for skin %X\n",m_dwSkinId); 3105 3106 // do we have it from the DLC pack? 3107 DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(this->customTextureUrl); 3108 3109 if(pDLCSkinFile!=NULL) 3110 { 3111 DWORD dwBoxC=pDLCSkinFile->getAdditionalBoxesCount(); 3112 if(dwBoxC!=0) 3113 { 3114 app.DebugPrintf("m_bCheckedForModelParts Got model parts from DLCskin for skin %X\n",m_dwSkinId); 3115 m_ppAdditionalModelParts=app.SetAdditionalSkinBoxes(m_dwSkinId,pDLCSkinFile->getAdditionalBoxes()); 3116 } 3117 3118 app.SetAnimOverrideBitmask(pDLCSkinFile->getSkinID(),pDLCSkinFile->getAnimOverrideBitmask()); 3119 3120 m_bCheckedForModelParts=true; 3121 } 3122 } 3123 3124 if(m_bCheckedForModelParts) setAnimOverrideBitmask(getSkinAnimOverrideBitmask(m_dwSkinId)); 3125 } 3126 return m_ppAdditionalModelParts; 3127} 3128 3129void Player::SetAdditionalModelParts(vector<ModelPart *> *ppAdditionalModelParts) 3130{ 3131 m_ppAdditionalModelParts=ppAdditionalModelParts; 3132} 3133 3134#if defined(__PS3__) || defined(__ORBIS__) 3135 3136Player::ePlayerNameValidState Player::GetPlayerNameValidState(void) 3137{ 3138 return m_ePlayerNameValidState; 3139} 3140 3141void Player::SetPlayerNameValidState(bool bState) 3142{ 3143 if(bState) 3144 { 3145 m_ePlayerNameValidState=ePlayerNameValid_True; 3146 } 3147 else 3148 { 3149 m_ePlayerNameValidState=ePlayerNameValid_False; 3150 3151 } 3152} 3153#endif