// 4J TODO // All the instanceof s from Java have been converted to dynamic_cast in this file // Once all the classes are finished it may be that we do not need to use dynamic_cast // for every test and a simple virtual function should suffice. We probably only need // dynamic_cast to find one of the classes that an object derives from, and not to find // the derived class itself (which should own the virtual GetType function) #include "stdafx.h" #include "JavaMath.h" #include "net.minecraft.h" #include "net.minecraft.world.h" #include "net.minecraft.stats.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.chunk.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.entity.h" #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" #include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.material.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.inventory.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.food.h" #include "Inventory.h" #include "Player.h" #include "ParticleTypes.h" #include "..\Minecraft.Client\Textures.h" #include "..\Minecraft.Client\LocalPlayer.h" #include "..\Minecraft.Client\HumanoidModel.h" #include "SoundTypes.h" void Player::_init() { inventory = shared_ptr( new Inventory( this ) ); userType = 0; score = 0; oBob = bob = 0.0f; swinging = false; swingTime = 0; //string name; dimension = 0; //string cloakTexture; xCloakO = yCloakO = zCloakO = 0.0; xCloak = yCloak = zCloak = 0.0; m_isSleeping = false; m_uiPlayerCurrentSkin=0; bedPosition = NULL; sleepCounter = 0; deathFadeCounter=0; bedOffsetX = bedOffsetY = bedOffsetZ = 0.0f; stats = NULL; respawnPosition = NULL; minecartAchievementPos = NULL; changingDimensionDelay = 20; isInsidePortal = false; portalTime = oPortalTime = 0.0f; dmgSpill = 0; fishing = nullptr; distanceWalk = distanceSwim = distanceFall = distanceClimb = distanceMinecart = distanceBoat = distancePig = 0; m_uiDebugOptions=0L; jumpTriggerTime = 0; takeXpDelay = 0; experienceLevel = totalExperience = 0; experienceProgress = 0.0f; useItem = nullptr; useItemDuration = 0; defaultWalkSpeed = 0.1f; defaultFlySpeed = 0.02f; m_uiGamePrivileges = 0; m_ppAdditionalModelParts=NULL; m_bCheckedForModelParts=false; m_bCheckedDLCForModelParts=false; #if defined(__PS3__) m_ePlayerNameValidState=ePlayerNameValid_NotSet; #endif enderChestInventory = shared_ptr(new PlayerEnderChestContainer()); m_bAwardedOnARail=false; } Player::Player(Level *level) : Mob( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called health = getMaxHealth(); _init(); MemSect(11); inventoryMenu = new InventoryMenu(inventory, !level->isClientSide, this); MemSect(0); containerMenu = inventoryMenu; heightOffset = 1.62f; Pos *spawnPos = level->getSharedSpawnPos(); this->moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); delete spawnPos; modelName = L"humanoid"; rotOffs = 180; flameTime = 20; textureIdx = TN_MOB_CHAR; // 4J - was L"/mob/char.png"; m_skinIndex = eDefaultSkins_Skin0; m_playerIndex = 0; m_dwSkinId = 0; m_dwCapeId = 0; // 4J Added m_xuid = INVALID_XUID; m_OnlineXuid = INVALID_XUID; //m_bShownOnMaps = true; setShowOnMaps(app.GetGameHostOption(eGameHostOption_Gamertags)!=0?true:false); m_bIsGuest = false; m_UUID = L""; } Player::~Player() { // TODO 4J //printf("A player has been destroyed.\n"); delete inventoryMenu; // 4J Stu - Fix for #10938 - CRASH - Game hardlocks when client has an open chest and Xbox Guide while host exits without saving. // If the container menu is not the inventory menu, then the player has a menu open. These get deleted when the xui scene // is destroyed, so we can not delete it here //if( containerMenu != inventoryMenu ) delete containerMenu; } int Player::getMaxHealth() { return MAX_HEALTH; } void Player::defineSynchedData() { this->Mob::defineSynchedData(); entityData->define(DATA_PLAYER_FLAGS_ID, (byte) 0); entityData->define(DATA_PLAYER_RUNNING_ID, (byte) 0); } shared_ptr Player::getUseItem() { return useItem; } int Player::getUseItemDuration() { return useItemDuration; } bool Player::isUsingItem() { return useItem != NULL; } int Player::getTicksUsingItem() { if (isUsingItem()) { return useItem->getUseDuration() - useItemDuration; } return 0; } void Player::releaseUsingItem() { if (useItem != NULL) { useItem->releaseUsing(level, dynamic_pointer_cast( shared_from_this() ), useItemDuration); // 4J Stu - Fix for various bugs where an incorrect bow was displayed when it broke (#70859,#93972,#93974) if (useItem->count == 0) { removeSelectedItem(); } } stopUsingItem(); } void Player::stopUsingItem() { useItem = nullptr; useItemDuration = 0; if (!level->isClientSide) { setUsingItemFlag(false); } } bool Player::isBlocking() { return isUsingItem() && Item::items[useItem->id]->getUseAnimation(useItem) == UseAnim_block; } void Player::tick() { if (useItem != NULL) { shared_ptr item = inventory->getSelected(); // 4J Stu - Fix for #45508 - TU5: Gameplay: Eating one piece of food will result in a second piece being eaten as well // 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) // 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) if (item == NULL || !item->equals(useItem) ) { stopUsingItem(); } else { if (useItemDuration <= 25 && useItemDuration % 4 == 0) { spawnEatParticles(item, 5); } if (--useItemDuration == 0) { if (!level->isClientSide) { completeUsingItem(); } } } } if (takeXpDelay > 0) takeXpDelay--; if (isSleeping()) { sleepCounter++; if (sleepCounter > SLEEP_DURATION) { sleepCounter = SLEEP_DURATION; } if (!level->isClientSide) { if (!checkBed()) { stopSleepInBed(true, true, false); } else if (level->isDay()) { stopSleepInBed(false, true, true); } } } else if (sleepCounter > 0) { sleepCounter++; if (sleepCounter >= (SLEEP_DURATION + WAKE_UP_DURATION)) { sleepCounter = 0; } } if(!isAlive()) { deathFadeCounter++; if (deathFadeCounter > DEATHFADE_DURATION) { deathFadeCounter = DEATHFADE_DURATION; } } this->Mob::tick(); if (!level->isClientSide) { if (containerMenu != NULL && !containerMenu->stillValid( dynamic_pointer_cast( shared_from_this() ) )) { closeContainer(); containerMenu = inventoryMenu; } } if (isOnFire() && (abilities.invulnerable || hasInvulnerablePrivilege() ) ) { clearFire(); } xCloakO = xCloak; yCloakO = yCloak; zCloakO = zCloak; double xca = x - xCloak; double yca = y - yCloak; double zca = z - zCloak; double m = 10; if (xca > m) xCloakO = xCloak = x; if (zca > m) zCloakO = zCloak = z; if (yca > m) yCloakO = yCloak = y; if (xca < -m) xCloakO = xCloak = x; if (zca < -m) zCloakO = zCloak = z; if (yca < -m) yCloakO = yCloak = y; xCloak += xca * 0.25; zCloak += zca * 0.25; yCloak += yca * 0.25; if (riding == NULL) { if( minecartAchievementPos != NULL ) { delete minecartAchievementPos; minecartAchievementPos = NULL; } } if (!level->isClientSide) { foodData.tick(dynamic_pointer_cast(shared_from_this())); } // 4J Stu Debugging if (!level->isClientSide) { static int count = 0; if( count++ == 100 ) { #if 0 #ifdef __PS3__ // #ifdef _DEBUG // // Drop some items so we have them in inventory to play with // this->drop( shared_ptr( new ItemInstance(Tile::recordPlayer) ) ); // this->drop( shared_ptr( new ItemInstance(Item::map) ) ); // this->drop( shared_ptr( new ItemInstance(Item::record_01) ) ); // this->drop( shared_ptr( new ItemInstance(Item::record_02) ) ); // this->drop( shared_ptr(new ItemInstance( Item::pickAxe_diamond, 1 )) ); // #endif #endif #endif // 4J-PB - Throw items out at the start of the level //this->drop( new ItemInstance( Item::pickAxe_diamond, 1 ) ); //this->drop( new ItemInstance( Tile::workBench, 1 ) ); //this->drop( new ItemInstance( Tile::treeTrunk, 8 ) ); //this->drop( shared_ptr( new ItemInstance( Item::milk, 3 ) ) ); //this->drop( shared_ptr( new ItemInstance( Item::sugar, 2 ) ) ); //this->drop( new ItemInstance( Tile::stoneBrick, 8 ) ); //this->drop( shared_ptr( new ItemInstance( Item::wheat, 3 ) ) ); //this->drop( shared_ptr( new ItemInstance( Item::egg, 1 ) ) ); //this->drop( new ItemInstance( Item::bow, 1 ) ); //this->drop( new ItemInstance( Item::arrow, 10 ) ); //this->drop( shared_ptr( new ItemInstance( Item::saddle, 10 ) ) ); //this->drop( shared_ptr( new ItemInstance( Tile::fence, 64 ) ) ); //this->drop( shared_ptr( new ItemInstance( Tile::fence, 64 ) ) ); //this->drop( shared_ptr( new ItemInstance( Tile::fence, 64 ) ) ); //shared_ptr mob = dynamic_pointer_cast(Pig::_class->newInstance( level )); //mob->moveTo(x+1, y, z+1, level->random->nextFloat() * 360, 0); //level->addEntity(mob); // 4J : WESTY : Spawn some wolves to befriend! /* shared_ptr mob1 = dynamic_pointer_cast(Wolf::_class->newInstance( level )); mob1->moveTo(x+1, y, z+1, level->random->nextFloat() * 360, 0); level->addEntity(mob1); shared_ptr mob2 = dynamic_pointer_cast(Wolf::_class->newInstance( level )); mob2->moveTo(x+2, y, z+1, level->random->nextFloat() * 360, 0); level->addEntity(mob2); shared_ptr mob3 = dynamic_pointer_cast(Wolf::_class->newInstance( level )); mob3->moveTo(x+1, y, z+2, level->random->nextFloat() * 360, 0); level->addEntity(mob3); shared_ptr mob4 = dynamic_pointer_cast(Wolf::_class->newInstance( level )); mob4->moveTo(x+3, y, z+1, level->random->nextFloat() * 360, 0); level->addEntity(mob4); shared_ptr mob5 = dynamic_pointer_cast(Wolf::_class->newInstance( level )); mob5->moveTo(x+1, y, z+3, level->random->nextFloat() * 360, 0); level->addEntity(mob5); */ // inventory.add(new ItemInstance(Item.potion, 1, PotionBrewing.THROWABLE_MASK | 0xc)); // addEffect(new MobEffectInstance(MobEffect.blindness.id, 60)); // increaseXp(10); { // ItemInstance itemInstance = new ItemInstance(Item.pickAxe_diamond); // itemInstance.enchant(Enchantment.diggingBonus, 3); // inventory.add(itemInstance); } } #if 0 // 4J Stu - This makes a tunnel with a powered track just over length to get the On A Rail achievement // It needs a few items at the start to get you going (a level and some powered rails) and of course a // minecart. For some reason some of the torches come off so it will also need some fixing along the way. static bool madeTrack = false; if( !madeTrack ) { this->drop( shared_ptr( new ItemInstance( Item::minecart, 1 ) ) ); this->drop( shared_ptr( new ItemInstance( Tile::goldenRail, 10 ) ) ); this->drop( shared_ptr( new ItemInstance( Tile::lever, 10 ) ) ); level->setTime( 0 ); int poweredCount = 0; for(int i = 10; i < 2800; ++i) { level->setTile(x+i,y-1,z-2,Tile::quartzBlock_Id); level->setTile(x+i,y,z-2,Tile::quartzBlock_Id); level->setTile(x+i,y+1,z-2,Tile::quartzBlock_Id); level->setTile(x+i,y+2,z-2,Tile::lightGem_Id); level->setTile(x+i,y+3,z-2,Tile::quartzBlock_Id); level->setTile(x+i,y-1,z-1,Tile::stoneBrick_Id); if(i%20 == 0) { level->setTile(x+i,y,z-1,Tile::notGate_on_Id); poweredCount = 4; } else { level->setTile(x+i,y,z-1,0); } level->setTile(x+i,y+1,z-1,0); level->setTile(x+i,y+2,z-1,0); level->setTile(x+i,y+3,z-1,0); level->setTile(x+i,y-1,z,Tile::stoneBrick_Id); if(poweredCount>0) { level->setTile(x+i,y,z,Tile::goldenRail_Id); --poweredCount; } else { level->setTile(x+i,y,z,Tile::rail_Id); } level->setTile(x+i,y+1,z,0); level->setTile(x+i,y+2,z,0); level->setTile(x+i,y+3,z,0); level->setTile(x+i,y-1,z+1,Tile::stoneBrick_Id); if((i+5)%20 == 0) { level->setTile(x+i,y,z+1,Tile::torch_Id); } else { level->setTile(x+i,y,z+1,0); } level->setTile(x+i,y+1,z+1,0); level->setTile(x+i,y+2,z+1,0); level->setTile(x+i,y+3,z+1,0); level->setTile(x+i,y-1,z+2,Tile::quartzBlock_Id); level->setTile(x+i,y,z+2,Tile::quartzBlock_Id); level->setTile(x+i,y+1,z+2,Tile::quartzBlock_Id); level->setTile(x+i,y+2,z+2,Tile::lightGem_Id); level->setTile(x+i,y+3,z+2,Tile::quartzBlock_Id); } madeTrack = true; } #endif } //End 4J sTU } void Player::spawnEatParticles(shared_ptr useItem, int count) { if (useItem->getUseAnimation() == UseAnim_drink) { level->playSound(shared_from_this(), eSoundType_RANDOM_DRINK, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); } if (useItem->getUseAnimation() == UseAnim_eat) { for (int i = 0; i < count; i++) { Vec3 *d = Vec3::newTemp((random->nextFloat() - 0.5) * 0.1, Math::random() * 0.1 + 0.1, 0); d->xRot(-xRot * PI / 180); d->yRot(-yRot * PI / 180); Vec3 *p = Vec3::newTemp((random->nextFloat() - 0.5) * 0.3, -random->nextFloat() * 0.6 - 0.3, 0.6); p->xRot(-xRot * PI / 180); p->yRot(-yRot * PI / 180); p = p->add(x, y + getHeadHeight(), z); level->addParticle(PARTICLE_ICONCRACK(useItem->getItem()->id,0), p->x, p->y, p->z, d->x, d->y + 0.05, d->z); } // 4J Stu - Was L"mob.eat" which doesnt exist level->playSound(shared_from_this(), eSoundType_RANDOM_EAT, 0.5f + 0.5f * random->nextInt(2), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); } } void Player::completeUsingItem() { if (useItem != NULL) { spawnEatParticles(useItem, 16); int oldCount = useItem->count; shared_ptr itemInstance = useItem->useTimeDepleted(level, dynamic_pointer_cast(shared_from_this())); if (itemInstance != useItem || (itemInstance != NULL && itemInstance->count != oldCount)) { inventory->items[inventory->selected] = itemInstance; if (itemInstance->count == 0) { inventory->items[inventory->selected] = nullptr; } } stopUsingItem(); } } void Player::handleEntityEvent(byte id) { if (id == EntityEvent::USE_ITEM_COMPLETE) { completeUsingItem(); } else { Mob::handleEntityEvent(id); } } bool Player::isImmobile() { return getHealth() <= 0 || isSleeping(); } void Player::closeContainer() { containerMenu = inventoryMenu; } void Player::ride(shared_ptr e) { if (riding != NULL && e == NULL) { if (!level->isClientSide) findStandUpPosition(riding); if (riding != NULL) { riding->rider = weak_ptr(); } riding = nullptr; return; } Mob::ride(e); } void Player::setPlayerDefaultSkin(EDefaultSkins skin) { #ifndef _CONTENT_PACKAGE wprintf(L"Setting default skin to %d for player %ls\n", skin, name.c_str() ); #endif m_skinIndex = skin; } void Player::setCustomSkin(DWORD skinId) { #ifndef _CONTENT_PACKAGE wprintf(L"Attempting to set skin to %08X for player %ls\n", skinId, name.c_str() ); #endif EDefaultSkins playerSkin = eDefaultSkins_ServerSelected; // reset the idle setIsIdle(false); setAnimOverrideBitmask(getSkinAnimOverrideBitmask(skinId)); if( !GET_IS_DLC_SKIN_FROM_BITMASK(skinId) ) { // GET_UGC_SKIN_ID_FROM_BITMASK will always be zero - this was for a possible custom skin editor skin DWORD ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(skinId); DWORD defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(skinId); if( ugcSkinIndex == 0 && defaultSkinIndex > 0 ) { playerSkin = (EDefaultSkins) defaultSkinIndex; } } if( playerSkin == eDefaultSkins_ServerSelected) { playerSkin = (EDefaultSkins)(m_playerIndex + 1); } // We always set a default skin, since we may be waiting for the player's custom skin to be transmitted setPlayerDefaultSkin( playerSkin ); m_dwSkinId = skinId; this->customTextureUrl = app.getSkinPathFromId(skinId); // set the new player additional boxes /*vector *pvModelParts=app.GetAdditionalModelParts(m_dwSkinId); if(pvModelParts==NULL) { // we don't have the data from the dlc skin yet app.DebugPrintf("Couldn't get model parts for skin %X\n",m_dwSkinId); // do we have it from the DLC pack? DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(this->customTextureUrl); if(pDLCSkinFile!=NULL) { DWORD dwBoxC=pDLCSkinFile->getAdditionalBoxesCount(); if(dwBoxC!=0) { app.DebugPrintf("Got model parts from DLCskin for skin %X\n",m_dwSkinId); pvModelParts=app.SetAdditionalSkinBoxes(m_dwSkinId,pDLCSkinFile->getAdditionalBoxes()); this->SetAdditionalModelParts(pvModelParts); } else { this->SetAdditionalModelParts(NULL); } app.SetAnimOverrideBitmask(pDLCSkinFile->getSkinID(),pDLCSkinFile->getAnimOverrideBitmask()); } else { this->SetAdditionalModelParts(NULL); } } else { app.DebugPrintf("Got model parts from app.GetAdditionalModelParts for skin %X\n",m_dwSkinId); this->SetAdditionalModelParts(pvModelParts); }*/ // reset the check for model parts m_bCheckedForModelParts=false; m_bCheckedDLCForModelParts=false; this->SetAdditionalModelParts(NULL); } unsigned int Player::getSkinAnimOverrideBitmask(DWORD skinId) { unsigned long bitmask = 0L; if( GET_IS_DLC_SKIN_FROM_BITMASK(skinId) ) { // Temp check for anim override switch( GET_DLC_SKIN_ID_FROM_BITMASK(skinId) ) { case 0x2://SP1_ZOMBIE: case 0x3://SP1_HEROBRINE: case 0xc8://SP3_ZOMBIE_PIGMAN: case 0xc9://SP3_ZOMBIE_HEROBRINE: case 0x1f8: // SPH_4JMUMMY case 0x220: // SPH_AOT_MUMMY case 0x23a: // SPH_CLIMAX_ZOMBIEBUSINESSMAN case 0x23d: // SPH_CLIMAX_EVILROBOT case 0x247: // SPH_CLIMAX_ZOMBIE case 0x194: // SOA_DEADLIGHT_SKINNY_ZOMBIE case 0x195: // SOA_DEADLIGHT_FEMALE_ZOMBIE bitmask = 1< 0) { this->customTextureUrl2 = Player::getCapePathFromId(capeId); } else { MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid()); if(pMojangData) { // Cape if(pMojangData->wchCape) { this->customTextureUrl2= pMojangData->wchCape; } else { if(app.DefaultCapeExists()) { this->customTextureUrl2= wstring(L"Special_Cape.png"); } else { this->customTextureUrl2= wstring(L""); } } } else { // if there is a custom default cloak, then set it here if(app.DefaultCapeExists()) { this->customTextureUrl2= wstring(L"Special_Cape.png"); } else { this->customTextureUrl2 =wstring(L""); } } } } DWORD Player::getCapeIdFromPath(const wstring &cape) { bool dlcCape = false; unsigned int capeId = 0; if(cape.size() >= 14) { dlcCape = cape.substr(0,3).compare(L"dlc") == 0; wstring capeValue = cape.substr(7,cape.size()); capeValue = capeValue.substr(0,capeValue.find_first_of(L'.')); std::wstringstream ss; // 4J Stu - dlc skins are numbered using decimal to make it easier for artists/people to number manually // Everything else is numbered using hex if(dlcCape) ss << std::dec << capeValue.c_str(); else ss << std::hex << capeValue.c_str(); ss >> capeId; capeId = MAKE_SKIN_BITMASK(dlcCape, capeId); } return capeId; } wstring Player::getCapePathFromId(DWORD capeId) { // 4J Stu - This function maps the encoded DWORD we store in the player profile // to a filename that is stored as a memory texture and shared between systems in game wchar_t chars[256]; if( GET_IS_DLC_SKIN_FROM_BITMASK(capeId) ) { // 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually swprintf(chars,256,L"dlccape%08d.png",GET_DLC_SKIN_ID_FROM_BITMASK(capeId)); } else { DWORD ugcCapeIndex = GET_UGC_SKIN_ID_FROM_BITMASK(capeId); DWORD defaultCapeIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(capeId); if( ugcCapeIndex == 0 ) { swprintf(chars,256,L"defcape%08X.png",defaultCapeIndex); } else { swprintf(chars,256,L"ugccape%08X.png",ugcCapeIndex); } } return chars; } void Player::ChangePlayerSkin() { if(app.vSkinNames.size()>0) { m_uiPlayerCurrentSkin++; if(m_uiPlayerCurrentSkin>app.vSkinNames.size()) { m_uiPlayerCurrentSkin=0; this->customTextureUrl=L""; } else { if(m_uiPlayerCurrentSkin>0) { // change this players custom texture url this->customTextureUrl=app.vSkinNames[m_uiPlayerCurrentSkin-1]; } } } } void Player::prepareCustomTextures() { MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid()); if(pMojangData) { // Skin if(pMojangData->wchSkin) { this->customTextureUrl= pMojangData->wchSkin; } // 4J Stu - Don't update the cape here, it gets set elsewhere // Cape //if(pMojangData->wchCape) //{ // this->customTextureUrl2= pMojangData->wchCape; //} //else //{ // if(app.DefaultCapeExists()) // { // this->customTextureUrl2= wstring(L"Default_Cape.png"); // } // else // { // this->customTextureUrl2= wstring(L""); // } //} } else { // 4J Stu - Don't update the cape here, it gets set elsewhere // if there is a custom default cloak, then set it here //if(app.DefaultCapeExists()) //{ // this->customTextureUrl2= wstring(L"Default_Cape.png"); //} //else //{ // this->customTextureUrl2 =wstring(L""); //} } /*cloakTexture = wstring(L"http://s3.amazonaws.com/MinecraftCloaks/").append( name ).append( L".png" );*/ //this->customTextureUrl2 = cloakTexture; } void Player::rideTick() { double preX = x, preY = y, preZ = z; float preYRot = yRot, preXRot = xRot; this->Mob::rideTick(); oBob = bob; bob = 0; checkRidingStatistiscs(x - preX, y - preY, z - preZ); // riding can be set to null inside 'Entity::rideTick()'. if ( riding != NULL && (riding->GetType() & eTYPE_PIG) == eTYPE_PIG ) { // 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 //xRot = preXRot; //yRot = preYRot; shared_ptr pig = dynamic_pointer_cast(riding); yBodyRot = pig->yBodyRot; while (yBodyRot - yBodyRotO < -180) yBodyRotO -= 360; while (yBodyRot - yBodyRotO >= 180) yBodyRotO += 360; } } void Player::resetPos() { heightOffset = 1.62f; setSize(0.6f, 1.8f); this->Mob::resetPos(); setHealth(getMaxHealth()); deathTime = 0; } int Player::getCurrentSwingDuration() { if (hasEffect(MobEffect::digSpeed)) { return SWING_DURATION - (1 + getEffect(MobEffect::digSpeed)->getAmplifier()) * 1; } if (hasEffect(MobEffect::digSlowdown)) { return SWING_DURATION + (1 + getEffect(MobEffect::digSlowdown)->getAmplifier()) * 2; } return SWING_DURATION; } void Player::serverAiStep() { int currentSwingDuration = getCurrentSwingDuration(); if (swinging) { swingTime++; if (swingTime >= currentSwingDuration) { swingTime = 0; swinging = false; } } else { swingTime = 0; } attackAnim = swingTime / (float) currentSwingDuration; } void Player::aiStep() { if (jumpTriggerTime > 0) jumpTriggerTime--; if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth()) { if (tickCount % 20 * 12 == 0) heal(1); } inventory->tick(); oBob = bob; this->Mob::aiStep(); this->walkingSpeed = abilities.getWalkingSpeed(); this->flyingSpeed = defaultFlySpeed; if (isSprinting()) { walkingSpeed += abilities.getWalkingSpeed() * 0.3f; flyingSpeed += defaultFlySpeed * 0.3f; } float tBob = (float) sqrt(xd * xd + zd * zd); // 4J added - we were getting a NaN with zero xd & zd if(( xd * xd + zd * zd ) < 0.00001f ) { tBob = 0.0f; } float tTilt = (float) atan(-yd * 0.2f) * 15.0f; if (tBob > 0.1f) tBob = 0.1f; if (!onGround || getHealth() <= 0) tBob = 0; if (onGround || getHealth() <= 0) tTilt = 0; bob += (tBob - bob) * 0.4f; tilt += (tTilt - tilt) * 0.8f; if (getHealth() > 0) { vector > *entities = level->getEntities(shared_from_this(), bb->grow(1, 0, 1)); if (entities != NULL) { AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { shared_ptr e = *it; //entities->at(i); if (!e->removed) { touch(e); } } } } } void Player::touch(shared_ptr entity) { entity->playerTouch( dynamic_pointer_cast( shared_from_this() ) ); } // 4J - Removed 1.0.1 //bool Player::addResource(int resource) //{ // return inventory->add(shared_ptr( new ItemInstance(resource, 1, 0) ) ); //} int Player::getScore() { return score; } void Player::die(DamageSource *source) { this->Mob::die(source); this->setSize(0.2f, 0.2f); setPos(x, y, z); yd = 0.1f; // 4J - TODO need to use a xuid if ( app.isXuidNotch( m_xuid ) ) { drop(shared_ptr( new ItemInstance(Item::apple, 1) ), true); } inventory->dropAll(); if (source != NULL) { xd = -Mth::cos((hurtDir + yRot) * PI / 180) * 0.1f; zd = -Mth::sin((hurtDir + yRot) * PI / 180) * 0.1f; } else { xd = zd = 0; } this->heightOffset = 0.1f; } void Player::awardKillScore(shared_ptr victim, int score) { this->score += score; } int Player::decreaseAirSupply(int currentSupply) { int oxygenBonus = EnchantmentHelper::getOxygenBonus(inventory); if (oxygenBonus > 0) { if (random->nextInt(oxygenBonus + 1) > 0) { // the oxygen bonus prevents us from drowning return currentSupply; } } return Mob::decreaseAirSupply(currentSupply); } bool Player::isShootable() { return true; } bool Player::isCreativeModeAllowed() { return true; } shared_ptr Player::drop() { return drop(inventory->removeItem(inventory->selected, 1), false); } shared_ptr Player::drop(shared_ptr item) { return drop(item, false); } shared_ptr Player::drop(shared_ptr item, bool randomly) { if (item == NULL) return nullptr; shared_ptr thrownItem = shared_ptr( new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, item) ); thrownItem->throwTime = 20 * 2; thrownItem->setThrower(getName()); float pow = 0.1f; if (randomly) { float _pow = random->nextFloat() * 0.5f; float dir = random->nextFloat() * PI * 2; thrownItem->xd = -sin(dir) * _pow; thrownItem->zd = cos(dir) * _pow; thrownItem->yd = 0.2f; } else { pow = 0.3f; thrownItem->xd = -sin(yRot / 180 * PI) * cos(xRot / 180 * PI) * pow; thrownItem->zd = cos(yRot / 180 * PI) * cos(xRot / 180 * PI) * pow; thrownItem->yd = -sin(xRot / 180 * PI) * pow + 0.1f; pow = 0.02f; float dir = random->nextFloat() * PI * 2; pow *= random->nextFloat(); thrownItem->xd += cos(dir) * pow; thrownItem->yd += (random->nextFloat() - random->nextFloat()) * 0.1f; thrownItem->zd += sin(dir) * pow; } reallyDrop(thrownItem); return thrownItem; } void Player::reallyDrop(shared_ptr thrownItem) { level->addEntity(thrownItem); } float Player::getDestroySpeed(Tile *tile) { float speed = inventory->getDestroySpeed(tile); int efficiency = EnchantmentHelper::getDiggingBonus(inventory); if (efficiency > 0 && inventory->canDestroy(tile)) { speed += (efficiency * efficiency + 1); } if (hasEffect(MobEffect::digSpeed)) { speed *= 1.0f + (getEffect(MobEffect::digSpeed)->getAmplifier() + 1) * .2f; } if (hasEffect(MobEffect::digSlowdown)) { speed *= 1.0f - (getEffect(MobEffect::digSlowdown)->getAmplifier() + 1) * .2f; } if (isUnderLiquid(Material::water) && !EnchantmentHelper::hasWaterWorkerBonus(inventory)) speed /= 5; // 4J Stu - onGround is set to true on the client when we are flying, which means // the dig speed is out of sync with the server. Removing this speed change when // flying so that we always dig as the same speed //if (!onGround) speed /= 5; return speed; } bool Player::canDestroy(Tile *tile) { return inventory->canDestroy(tile); } void Player::readAdditionalSaveData(CompoundTag *entityTag) { Mob::readAdditionalSaveData(entityTag); ListTag *inventoryList = (ListTag *) entityTag->getList(L"Inventory"); inventory->load(inventoryList); dimension = entityTag->getInt(L"Dimension"); m_isSleeping = entityTag->getBoolean(L"Sleeping"); sleepCounter = entityTag->getShort(L"SleepTimer"); experienceProgress = entityTag->getFloat(L"XpP"); experienceLevel = entityTag->getInt(L"XpLevel"); totalExperience = entityTag->getInt(L"XpTotal"); if (m_isSleeping) { bedPosition = new Pos( Mth::floor(x), Mth::floor(y), Mth::floor(z)); stopSleepInBed(true, true, false); } if (entityTag->contains(L"SpawnX") && entityTag->contains(L"SpawnY") && entityTag->contains(L"SpawnZ")) { respawnPosition = new Pos(entityTag->getInt(L"SpawnX"), entityTag->getInt(L"SpawnY"), entityTag->getInt(L"SpawnZ")); } foodData.readAdditionalSaveData(entityTag); abilities.loadSaveData(entityTag); if (entityTag->contains(L"EnderItems")) { ListTag *enderItemsList = (ListTag *) entityTag->getList(L"EnderItems"); enderChestInventory->setItemsByTag(enderItemsList); } // 4J Added m_uiGamePrivileges = entityTag->getInt(L"GamePrivileges"); } void Player::addAdditonalSaveData(CompoundTag *entityTag) { Mob::addAdditonalSaveData(entityTag); entityTag->put(L"Inventory", inventory->save(new ListTag())); entityTag->putInt(L"Dimension", dimension); entityTag->putBoolean(L"Sleeping", m_isSleeping); entityTag->putShort(L"SleepTimer", (short) sleepCounter); entityTag->putFloat(L"XpP", experienceProgress); entityTag->putInt(L"XpLevel", experienceLevel); entityTag->putInt(L"XpTotal", totalExperience); if (respawnPosition != NULL) { entityTag->putInt(L"SpawnX", respawnPosition->x); entityTag->putInt(L"SpawnY", respawnPosition->y); entityTag->putInt(L"SpawnZ", respawnPosition->z); } foodData.addAdditonalSaveData(entityTag); abilities.addSaveData(entityTag); entityTag->put(L"EnderItems", enderChestInventory->createTag()); // 4J Added entityTag->putInt(L"GamePrivileges",m_uiGamePrivileges); } Pos *Player::getRespawnPosition(Level *level, CompoundTag *entityTag) { if (entityTag->contains(L"SpawnX") && entityTag->contains(L"SpawnY") && entityTag->contains(L"SpawnZ")) { return new Pos(entityTag->getInt(L"SpawnX"), entityTag->getInt(L"SpawnY"), entityTag->getInt(L"SpawnZ")); } return level->getSharedSpawnPos(); } bool Player::openContainer(shared_ptr container) { return true; } bool Player::startEnchanting(int x, int y, int z) { return true; } bool Player::startRepairing(int x, int y, int z) { return true; } bool Player::startCrafting(int x, int y, int z) { return true; } void Player::take(shared_ptr e, int orgCount) { } float Player::getHeadHeight() { return 0.12f; } void Player::setDefaultHeadHeight() { heightOffset = 1.62f; } bool Player::hurt(DamageSource *source, int dmg) { if ( hasInvulnerablePrivilege() || (abilities.invulnerable && !source->isBypassInvul()) ) return false; // 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. if ( source == DamageSource::fall && isAllowedToFly() && abilities.flying ) return false; noActionTime = 0; if (getHealth() <= 0) return false; if (isSleeping() && !level->isClientSide) { stopSleepInBed(true, true, false); } if ( source->scalesWithDifficulty() ) { if (level->difficulty == Difficulty::PEACEFUL) dmg = 0; if (level->difficulty == Difficulty::EASY) dmg = dmg / 2 + 1; if (level->difficulty == Difficulty::HARD) dmg = dmg * 3 / 2; } if (dmg == 0) return false; shared_ptr attacker = source->getEntity(); if ( dynamic_pointer_cast( attacker ) != NULL ) { if ((dynamic_pointer_cast(attacker))->owner != NULL) { attacker = (dynamic_pointer_cast(attacker))->owner; } } if ( dynamic_pointer_cast( attacker ) != NULL ) { // aggreviate all pet wolves nearby directAllTameWolvesOnTarget(dynamic_pointer_cast(attacker), false); } return this->Mob::hurt(source, dmg); } int Player::getDamageAfterMagicAbsorb(DamageSource *damageSource, int damage) { int remainingDamage = Mob::getDamageAfterMagicAbsorb(damageSource, damage); if (remainingDamage <= 0) { return 0; } int enchantmentArmor = EnchantmentHelper::getDamageProtection(inventory, damageSource); if (enchantmentArmor > 20) { enchantmentArmor = 20; } if (enchantmentArmor > 0 && enchantmentArmor <= 20) { int absorb = 25 - enchantmentArmor; int v = remainingDamage * absorb + dmgSpill; remainingDamage = v / 25; dmgSpill = v % 25; } return remainingDamage; } bool Player::isPlayerVersusPlayer() { return false; } void Player::directAllTameWolvesOnTarget(shared_ptr target, bool skipSitting) { // filter un-attackable mobs if ((dynamic_pointer_cast( target ) != NULL) || (dynamic_pointer_cast( target) != NULL)) { return; } // never target wolves that has this player as owner if (dynamic_pointer_cast(target) != NULL) { shared_ptr wolfTarget = dynamic_pointer_cast(target); if (wolfTarget->isTame() && m_UUID.compare( wolfTarget->getOwnerUUID() ) == 0 ) { return; } } if ((dynamic_pointer_cast( target ) != NULL) && !isPlayerVersusPlayer()) { // pvp is off return; } // TODO: Optimize this? Most of the time players wont have pets: vector > *nearbyWolves = level->getEntitiesOfClass(typeid(Wolf), AABB::newTemp(x, y, z, x + 1, y + 1, z + 1)->grow(16, 4, 16)); AUTO_VAR(itEnd, nearbyWolves->end()); for (AUTO_VAR(it, nearbyWolves->begin()); it != itEnd; it++) { shared_ptr wolf = dynamic_pointer_cast(*it);; if (wolf->isTame() && wolf->getAttackTarget() == NULL && m_UUID.compare( wolf->getOwnerUUID() ) == 0) { if (!skipSitting || !wolf->isSitting()) { wolf->setSitting(false); wolf->setAttackTarget(target); } } } delete nearbyWolves; } void Player::hurtArmor(int damage) { inventory->hurtArmor(damage); } int Player::getArmorValue() { return inventory->getArmorValue(); } float Player::getArmorCoverPercentage() { int count = 0; for (int i = 0; i < inventory->armor.length; i++) { if (inventory->armor[i] != NULL) { count++; } } return (float) count / (float) inventory->armor.length; } void Player::actuallyHurt(DamageSource *source, int dmg) { if (!source->isBypassArmor() && isBlocking()) { dmg = (1 + dmg) >> 1; } dmg = getDamageAfterArmorAbsorb(source, dmg); dmg = getDamageAfterMagicAbsorb(source, dmg); causeFoodExhaustion(source->getFoodExhaustion()); //this->Mob::actuallyHurt(source, dmg); health -= dmg; } bool Player::openFurnace(shared_ptr container) { return true; } bool Player::openTrap(shared_ptr container) { return true; } void Player::openTextEdit(shared_ptr sign) { } bool Player::openBrewingStand(shared_ptr brewingStand) { return true; } bool Player::openTrading(shared_ptr traderTarget) { return true; } /** * Opens an iteminstance-dependent user interface. * * @param itemInstance */ void Player::openItemInstanceGui(shared_ptr itemInstance) { } bool Player::interact(shared_ptr entity) { if (entity->interact( dynamic_pointer_cast( shared_from_this() ) )) return true; shared_ptr item = getSelectedItem(); if (item != NULL && dynamic_pointer_cast( entity ) != NULL) { // 4J - PC Comments // Hack to prevent item stacks from decrementing if the player has // the ability to instabuild if(this->abilities.instabuild) item = item->copy(); if(item->interactEnemy(dynamic_pointer_cast(entity))) { // 4J - PC Comments // Don't remove the item in hand if the player has the ability // to // instabuild if (item->count <= 0 && !this->abilities.instabuild) { removeSelectedItem(); } return true; } } return false; } shared_ptr Player::getSelectedItem() { return inventory->getSelected(); } void Player::removeSelectedItem() { inventory->setItem(inventory->selected, nullptr); } double Player::getRidingHeight() { return heightOffset - 0.5f; } void Player::swing() { if (!swinging || swingTime >= getCurrentSwingDuration() / 2 || swingTime < 0) { swingTime = -1; swinging = true; } } void Player::attack(shared_ptr entity) { if (!entity->isAttackable()) { return; } int dmg = inventory->getAttackDamage(entity); if (hasEffect(MobEffect::damageBoost)) { dmg += (3 << getEffect(MobEffect::damageBoost)->getAmplifier()); } if (hasEffect(MobEffect::weakness)) { dmg -= (2 << getEffect(MobEffect::weakness)->getAmplifier()); } int knockback = 0; int magicBoost = 0; shared_ptr mob = dynamic_pointer_cast(entity); if (mob != NULL) { magicBoost = EnchantmentHelper::getDamageBonus(inventory, mob); knockback += EnchantmentHelper::getKnockbackBonus(inventory, mob); } if (isSprinting()) { knockback += 1; } if (dmg > 0 || magicBoost > 0) { bool bCrit = fallDistance > 0 && !onGround && !onLadder() && !isInWater() && !hasEffect(MobEffect::blindness) && riding == NULL && mob != NULL; if (bCrit) { dmg += random->nextInt(dmg / 2 + 2); } dmg += magicBoost; // Ensure we put the entity on fire if we're hitting with a // fire-enchanted weapon bool setOnFireTemporatily = false; int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast(shared_from_this())); if (dynamic_pointer_cast(entity) && fireAspect > 0 && !entity->isOnFire()) { setOnFireTemporatily = true; entity->setOnFire(1); } DamageSource *damageSource = DamageSource::playerAttack(dynamic_pointer_cast(shared_from_this())); bool wasHurt = entity->hurt(damageSource, dmg); delete damageSource; if (wasHurt) { if (knockback > 0) { entity->push(-Mth::sin(yRot * PI / 180) * knockback * .5f, 0.1, Mth::cos(yRot * PI / 180) * knockback * .5f); xd *= 0.6; zd *= 0.6; setSprinting(false); } if (bCrit) { crit(entity); } if (magicBoost > 0) { magicCrit(entity); } if (dmg >= 18) { awardStat(GenericStats::overkill(),GenericStats::param_overkill(dmg)); } setLastHurtMob(entity); shared_ptr mob = dynamic_pointer_cast(entity); if (mob) { ThornsEnchantment::doThornsAfterAttack(shared_from_this(), mob, random); } } shared_ptr item = getSelectedItem(); if (item != NULL && dynamic_pointer_cast( entity ) != NULL) { item->hurtEnemy(dynamic_pointer_cast(entity), dynamic_pointer_cast( shared_from_this() ) ); if (item->count <= 0) { removeSelectedItem(); } } if (dynamic_pointer_cast( entity ) != NULL) { if (entity->isAlive()) { directAllTameWolvesOnTarget(dynamic_pointer_cast(entity), true); } // 4J Stu - Brought forward wasHurt check to Fix 66140 - Bug: Fire Aspect bypasses "Player v Player" being Disabled if (fireAspect > 0 && wasHurt) { entity->setOnFire(fireAspect * 4); } else if (setOnFireTemporatily) { entity->clearFire(); } } causeFoodExhaustion(FoodConstants::EXHAUSTION_ATTACK); } } void Player::crit(shared_ptr entity) { } void Player::magicCrit(shared_ptr entity) { } void Player::respawn() { deathFadeCounter=0; } void Player::animateRespawn(shared_ptr player, Level *level) { for (int i = 0; i < 45; i++) { float angle = i * PI * 4.0f / 25.0f; float xo = Mth::cos(angle) * 0.7f; float zo = Mth::sin(angle) * 0.7f; level->addParticle(eParticleType_netherportal, player->x + xo, player->y - player->heightOffset + 1.62f - i * .05f, player->z + zo, 0, 0, 0); } } Slot *Player::getInventorySlot(int slotId) { return NULL; } void Player::remove() { this->Mob::remove(); inventoryMenu->removed( dynamic_pointer_cast( shared_from_this() ) ); if (containerMenu != NULL) { containerMenu->removed( dynamic_pointer_cast( shared_from_this() ) ); } } bool Player::isInWall() { return !m_isSleeping && this->Mob::isInWall(); } bool Player::isLocalPlayer() { return false; } Player::BedSleepingResult Player::startSleepInBed(int x, int y, int z, bool bTestUse) { if (!level->isClientSide || bTestUse) { if (isSleeping() || !isAlive()) { return OTHER_PROBLEM; } if (!level->dimension->isNaturalDimension()) { // may not sleep in this dimension return NOT_POSSIBLE_HERE; } // 4J-PB - I'm going to move the position of these tests below // The distance check should be before the day check, otherwise you can use the bed in daytime from far away // and you'll get the message about only sleeping at night if (abs(this->x - x) > 3 || abs(this->y - y) > 2 || abs(this->z - z) > 3) { // too far away return TOO_FAR_AWAY; } if (!bTestUse) { // 4J-PB - We still want the tooltip for Sleep double hRange = 8; double vRange = 5; vector > *monsters = level->getEntitiesOfClass(typeid(Monster), AABB::newTemp(x - hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange)); if (!monsters->empty()) { return NOT_SAFE; } delete monsters; } // This causes a message to be displayed, so we do want to show the tooltip in test mode if (!bTestUse && level->isDay()) { // may not sleep during day return NOT_POSSIBLE_NOW; } } if(bTestUse) { // 4J-PB - we're just testing use, and we get here, then the bed can be used return OK; } // 4J Stu - You can use a bed from within a minecart, and this causes all sorts of problems. ride(nullptr); setSize(0.2f, 0.2f); heightOffset = .2f; if (level->hasChunkAt(x, y, z)) { int data = level->getData(x, y, z); int direction = BedTile::getDirection(data); float xo = .5f, zo = .5f; switch (direction) { case Direction::SOUTH: zo = .9f; break; case Direction::NORTH: zo = .1f; break; case Direction::WEST: xo = .1f; break; case Direction::EAST: xo = .9f; break; } setBedOffset(direction); setPos(x + xo, y + 15.0f / 16.0f, z + zo); } else { setPos(x + .5f, y + 15.0f / 16.0f, z + .5f); } m_isSleeping = true; sleepCounter = 0; bedPosition = new Pos(x, y, z); xd = zd = yd = 0; if (!level->isClientSide) { level->updateSleepingPlayerList(); } return OK; } void Player::setBedOffset(int bedDirection) { // place position on pillow and feet at bottom bedOffsetX = 0; bedOffsetZ = 0; switch (bedDirection) { case Direction::SOUTH: bedOffsetZ = -1.8f; break; case Direction::NORTH: bedOffsetZ = 1.8f; break; case Direction::WEST: bedOffsetX = 1.8f; break; case Direction::EAST: bedOffsetX = -1.8f; break; } } /** * * @param forcefulWakeUp * If the player has been forced to wake up. When this happens, * the client will skip the wake-up animation. For example, when * the player is hurt or the bed is destroyed. * @param updateLevelList * If the level's sleeping player list needs to be updated. This * is usually the case. * @param saveRespawnPoint * TODO */ void Player::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint) { setSize(0.6f, 1.8f); setDefaultHeadHeight(); Pos *pos = bedPosition; Pos *standUp = bedPosition; if (pos != NULL && level->getTile(pos->x, pos->y, pos->z) == Tile::bed_Id) { BedTile::setOccupied(level, pos->x, pos->y, pos->z, false); standUp = BedTile::findStandUpPosition(level, pos->x, pos->y, pos->z, 0); if (standUp == NULL) { standUp = new Pos(pos->x, pos->y + 1, pos->z); } setPos(standUp->x + .5f, standUp->y + heightOffset + .1f, standUp->z + .5f); } m_isSleeping = false; if (!level->isClientSide && updateLevelList) { level->updateSleepingPlayerList(); } if (forcefulWakeUp) { sleepCounter = 0; } else { sleepCounter = SLEEP_DURATION; } if (saveRespawnPoint) { setRespawnPosition(bedPosition); } } bool Player::checkBed() { return (level->getTile(bedPosition->x, bedPosition->y, bedPosition->z) == Tile::bed_Id); } Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos) { // make sure the chunks around the bed exist ChunkSource *chunkSource = level->getChunkSource(); chunkSource->create((pos->x - 3) >> 4, (pos->z - 3) >> 4); chunkSource->create((pos->x + 3) >> 4, (pos->z - 3) >> 4); chunkSource->create((pos->x - 3) >> 4, (pos->z + 3) >> 4); chunkSource->create((pos->x + 3) >> 4, (pos->z + 3) >> 4); // make sure the bed is still standing if (level->getTile(pos->x, pos->y, pos->z) != Tile::bed_Id) { return NULL; } // make sure the bed still has a stand-up position Pos *standUp = BedTile::findStandUpPosition(level, pos->x, pos->y, pos->z, 0); return standUp; } float Player::getSleepRotation() { if (bedPosition != NULL) { int data = level->getData(bedPosition->x, bedPosition->y, bedPosition->z); int direction = BedTile::getDirection(data); switch (direction) { case Direction::SOUTH: return 90; case Direction::WEST: return 0; case Direction::NORTH: return 270; case Direction::EAST: return 180; } } return 0; } bool Player::isSleeping() { return m_isSleeping; } bool Player::isSleepingLongEnough() { return m_isSleeping && sleepCounter >= SLEEP_DURATION; } int Player::getSleepTimer() { return sleepCounter; } // 4J-PB - added for death fade int Player::getDeathFadeTimer() { return deathFadeCounter; } bool Player::getPlayerFlag(int flag) { return (entityData->getByte(DATA_PLAYER_FLAGS_ID) & (1 << flag)) != 0; } void Player::setPlayerFlag(int flag, bool value) { byte currentValue = entityData->getByte(DATA_PLAYER_FLAGS_ID); if (value) { entityData->set(DATA_PLAYER_FLAGS_ID, (byte) (currentValue | (1 << flag))); } else { entityData->set(DATA_PLAYER_FLAGS_ID, (byte) (currentValue & ~(1 << flag))); } } /** * This method is currently only relevant to client-side players. It will * try to load the messageId from the language file and display it to the * client. */ void Player::displayClientMessage(int messageId) { } Pos *Player::getRespawnPosition() { return respawnPosition; } void Player::setRespawnPosition(Pos *respawnPosition) { if (respawnPosition != NULL) { this->respawnPosition = new Pos(*respawnPosition); } else { this->respawnPosition = NULL; } } void Player::awardStat(Stat *stat, byteArray paramBlob) { if (paramBlob.data != NULL) { delete [] paramBlob.data; } } void Player::jumpFromGround() { this->Mob::jumpFromGround(); // 4J Stu - This seems to have been missed from 1.7.3, but do we care? //awardStat(Stats::jump, 1); if (isSprinting()) { causeFoodExhaustion(FoodConstants::EXHAUSTION_SPRINT_JUMP); } else { causeFoodExhaustion(FoodConstants::EXHAUSTION_JUMP); } } void Player::travel(float xa, float ya) { double preX = x, preY = y, preZ = z; if (abilities.flying && riding == NULL) { double ydo = this->yd; float ofs = flyingSpeed; flyingSpeed = abilities.getFlyingSpeed(); this->Mob::travel(xa, ya); this->yd = ydo * 0.6; flyingSpeed = ofs; } else { this->Mob::travel(xa, ya); } checkMovementStatistiscs(x - preX, y - preY, z - preZ); } void Player::checkMovementStatistiscs(double dx, double dy, double dz) { if (riding != NULL) { return; } if (isUnderLiquid(Material::water)) { int distance = (int) Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f); if (distance > 0) { //awardStat(Stats::diveOneCm, distance); causeFoodExhaustion(FoodConstants::EXHAUSTION_SWIM * distance * .01f); } } else if (isInWater()) { int horizontalDistance = (int) Math::round(sqrt(dx * dx + dz * dz) * 100.0f); if (horizontalDistance > 0) { distanceSwim += horizontalDistance; if( distanceSwim >= 100 ) { int newDistance = distanceSwim - (distanceSwim % 100); distanceSwim -= newDistance; awardStat( GenericStats::swimOneM(), GenericStats::param_swim(newDistance/100) ); } causeFoodExhaustion(FoodConstants::EXHAUSTION_SWIM * horizontalDistance * .01f); } } else if (onLadder()) { if (dy > 0) { distanceClimb += (int) Math::round(dy * 100.0f); if( distanceClimb >= 100 ) { int newDistance = distanceClimb - (distanceClimb % 100); distanceClimb -= newDistance; awardStat( GenericStats::climbOneM(), GenericStats::param_climb(newDistance/100) ); } } } else if (onGround) { int horizontalDistance = (int) Math::round(sqrt(dx * dx + dz * dz) * 100.0f); if (horizontalDistance > 0) { distanceWalk += horizontalDistance; if( distanceWalk >= 100 ) { int newDistance = distanceWalk - (distanceWalk % 100); distanceWalk -= newDistance; awardStat( GenericStats::walkOneM(), GenericStats::param_walk(newDistance/100) ); } if (isSprinting()) { causeFoodExhaustion(FoodConstants::EXHAUSTION_SPRINT * horizontalDistance * .01f); } else { causeFoodExhaustion(FoodConstants::EXHAUSTION_WALK * horizontalDistance * .01f); } } } } void Player::checkRidingStatistiscs(double dx, double dy, double dz) { if (riding != NULL) { int distance = (int) Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f); if (distance > 0) { if ( dynamic_pointer_cast( riding ) ) { distanceMinecart += distance; if( distanceMinecart >= 100 ) { int newDistance = distanceMinecart - (distanceMinecart % 100); distanceMinecart -= newDistance; awardStat( GenericStats::minecartOneM(), GenericStats::param_minecart(newDistance/100) ); } int dist = 0; if (minecartAchievementPos == NULL) { minecartAchievementPos = new Pos(Mth::floor(x), Mth::floor(y), Mth::floor(z)); } // 4J-PB - changed this because our world isn't big enough to go 1000m else { // 4-JEV, changed slightly to add extra parameters for event on durango. int dist = minecartAchievementPos->dist(Mth::floor(x), Mth::floor(y), Mth::floor(z)); if ((m_bAwardedOnARail==false) && (dist >= 500)) { awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); m_bAwardedOnARail=true; } } } else if (dynamic_pointer_cast( riding ) != NULL) { distanceBoat += distance; if( distanceBoat >= 100 ) { int newDistance = distanceBoat - (distanceBoat % 100); distanceBoat -= newDistance; awardStat(GenericStats::boatOneM(), GenericStats::param_boat(newDistance/100) ); } } else if (dynamic_pointer_cast( riding ) != NULL) { distancePig += distance; if( distancePig >= 100 ) { int newDistance = distancePig - (distancePig % 100); distancePig -= newDistance; awardStat(GenericStats::pigOneM(), GenericStats::param_pig(newDistance/100) ); } } } } } void Player::causeFallDamage(float distance) { if (abilities.mayfly) return; if (distance >= 2) { distanceFall += (int) Math::round(distance * 100.0); if( distanceFall >= 100 ) { int newDistance = distanceFall - (distanceFall % 100); distanceFall -= newDistance; awardStat(GenericStats::fallOneM(), GenericStats::param_fall(newDistance/100) ); } } this->Mob::causeFallDamage(distance); } void Player::killed(shared_ptr mob) { // 4J-PB - added the lavaslime enemy - fix for #64007 - TU7: Code: Achievements: TCR#073: Killing Magma Cubes doesn't unlock "Monster Hunter" Achievement. if( dynamic_pointer_cast( mob ) != NULL || mob->GetType() == eTYPE_GHAST || mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME || mob->GetType() == eTYPE_ENDERDRAGON) { awardStat(GenericStats::killEnemy(), GenericStats::param_noArgs()); switch( mob->GetType() ) { case eTYPE_CREEPER: awardStat(GenericStats::killsCreeper(), GenericStats::param_noArgs()); break; case eTYPE_SKELETON: if( mob->isRiding() && mob->riding->GetType() == eTYPE_SPIDER ) awardStat(GenericStats::killsSpiderJockey(), GenericStats::param_noArgs()); else awardStat(GenericStats::killsSkeleton(), GenericStats::param_noArgs()); break; case eTYPE_SPIDER: if( mob->rider.lock() != NULL && mob->rider.lock()->GetType() == eTYPE_SKELETON ) awardStat(GenericStats::killsSpiderJockey(), GenericStats::param_noArgs()); else awardStat(GenericStats::killsSpider(), GenericStats::param_noArgs()); break; case eTYPE_ZOMBIE: awardStat(GenericStats::killsZombie(), GenericStats::param_noArgs()); break; case eTYPE_PIGZOMBIE: if( level->dimension->id == 0 ) awardStat(GenericStats::killsZombiePigman(), GenericStats::param_noArgs()); else awardStat(GenericStats::killsNetherZombiePigman(), GenericStats::param_noArgs()); break; case eTYPE_GHAST: awardStat(GenericStats::killsGhast(), GenericStats::param_noArgs()); break; case eTYPE_SLIME: awardStat(GenericStats::killsSlime(), GenericStats::param_noArgs()); break; case eTYPE_ENDERDRAGON: awardStat(GenericStats::killsEnderdragon(), GenericStats::param_noArgs()); break; } } else if( mob->GetType() == eTYPE_COW ) { awardStat(GenericStats::killCow(), GenericStats::param_noArgs()); } } Icon *Player::getItemInHandIcon(shared_ptr item, int layer) { Icon *icon = Mob::getItemInHandIcon(item, layer); if (item->id == Item::fishingRod->id && fishing != NULL) { icon = Item::fishingRod->getEmptyIcon(); } else if (item->getItem()->hasMultipleSpriteLayers()) { return item->getItem()->getLayerIcon(item->getAuxValue(), layer); } else if (useItem != NULL && item->id == Item::bow_Id) { int ticksHeld = (item->getUseDuration() - useItemDuration); if (ticksHeld >= BowItem::MAX_DRAW_DURATION - 2) { return Item::bow->getDrawnIcon(2); } if (ticksHeld > (2 * BowItem::MAX_DRAW_DURATION) / 3) { return Item::bow->getDrawnIcon(1); } if (ticksHeld > 0) { return Item::bow->getDrawnIcon(0); } } return icon; } shared_ptr Player::getArmor(int pos) { return inventory->getArmor(pos); } void Player::handleInsidePortal() { if (changingDimensionDelay > 0) { changingDimensionDelay = 10; return; } isInsidePortal = true; } void Player::increaseXp(int i) { // Update xp calculations from 1.3 score += i; int max = INT_MAX - totalExperience; if (i > max) { i = max; } experienceProgress += (float) i / getXpNeededForNextLevel(); totalExperience += i; while (experienceProgress >= 1) { experienceProgress = (experienceProgress - 1) * getXpNeededForNextLevel(); levelUp(); experienceProgress /= getXpNeededForNextLevel(); } } void Player::withdrawExperienceLevels(int amount) { experienceLevel -= amount; if (experienceLevel < 0) { experienceLevel = 0; } } int Player::getXpNeededForNextLevel() { // Update xp calculations from 1.3 if (experienceLevel >= 30) { return 17 + 15 * 3 + (experienceLevel - 30) * 7; } if (experienceLevel >= 15) { return 17 + (experienceLevel - 15) * 3; } return 17; } void Player::levelUp() { experienceLevel++; } /** * This method adds on to the player's exhaustion, which may decrease the * player's food level. * * @param amount * Amount of exhaustion to add, between 0 and 20 (setting it to * 20 will guarantee that at least 1, and at most 4, food points * are deducted). See FoodConstants for cost suggestions. */ void Player::causeFoodExhaustion(float amount) { if( isAllowedToIgnoreExhaustion() || ( isAllowedToFly() && abilities.flying) ) return; if (abilities.invulnerable || hasInvulnerablePrivilege() ) return; // 4J Stu - Added 1.8.2 bug fix (TU6) - If players cannot eat, then their food bar should not decrease due to exhaustion if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) return; if (!level->isClientSide) { foodData.addExhaustion(amount); } } FoodData *Player::getFoodData() { return &foodData; } bool Player::canEat(bool magicalItem) { return (magicalItem || foodData.needsFood()) && !abilities.invulnerable && !hasInvulnerablePrivilege(); } bool Player::isHurt() { return getHealth() > 0 && getHealth() < getMaxHealth(); } void Player::startUsingItem(shared_ptr instance, int duration) { if (instance == useItem) return; useItem = instance; useItemDuration = duration; if (!level->isClientSide) { setUsingItemFlag(true); } // 4J-JEV, hook for ItemUsed event, and ironbelly achievement. awardStat(GenericStats::itemsUsed(instance->getItem()->id), GenericStats::param_itemsUsed(dynamic_pointer_cast(shared_from_this()),instance)); #if defined _EXTENDED_ACHIEVEMENTS if ( (instance->getItem()->id == Item::rotten_flesh_Id) && (getFoodData()->getFoodLevel() == 0) ) awardStat(GenericStats::ironBelly(), GenericStats::param_ironBelly()); #endif } bool Player::mayBuild(int x, int y, int z) { return abilities.mayBuild; } int Player::getExperienceReward(shared_ptr killedBy) { int reward = experienceLevel * 7; if (reward > 100) { return 100; } return reward; } bool Player::isAlwaysExperienceDropper() { // players always drop experience return true; } wstring Player::getAName() { return name; } void Player::changeDimension(int i) { } void Player::restoreFrom(shared_ptr oldPlayer, bool restoreAll) { if(restoreAll) { inventory->replaceWith(oldPlayer->inventory); health = oldPlayer->health; foodData = oldPlayer->foodData; experienceLevel = oldPlayer->experienceLevel; totalExperience = oldPlayer->totalExperience; experienceProgress = oldPlayer->experienceProgress; score = oldPlayer->score; for(AUTO_VAR(it, oldPlayer->activeEffects.begin()); it != oldPlayer->activeEffects.end(); ++it) { MobEffectInstance *instance = it->second; addEffectNoUpdate( instance ); } oldPlayer->activeEffects.clear(); } enderChestInventory = oldPlayer->enderChestInventory; } bool Player::makeStepSound() { return !abilities.flying; } void Player::onUpdateAbilities() { } void Player::setGameMode(GameType *mode) { } wstring Player::getName() { return name; } wstring Player::getDisplayName() { return displayName; } //Language getLanguage() { return Language.getInstance(); } //String localize(String key, Object... args) { return getLanguage().getElement(key, args); } shared_ptr Player::getEnderChestInventory() { return enderChestInventory; } shared_ptr Player::getCarriedItem() { return inventory->getSelected(); } bool Player::isInvisibleTo(shared_ptr player) { return isInvisible(); } int Player::getTexture() { switch(m_skinIndex) { case eDefaultSkins_Skin0: return TN_MOB_CHAR; // 4J - was L"/mob/char.png"; case eDefaultSkins_Skin1: return TN_MOB_CHAR1; // 4J - was L"/mob/char1.png"; case eDefaultSkins_Skin2: return TN_MOB_CHAR2; // 4J - was L"/mob/char2.png"; case eDefaultSkins_Skin3: return TN_MOB_CHAR3; // 4J - was L"/mob/char3.png"; case eDefaultSkins_Skin4: return TN_MOB_CHAR4; // 4J - was L"/mob/char4.png"; case eDefaultSkins_Skin5: return TN_MOB_CHAR5; // 4J - was L"/mob/char5.png"; case eDefaultSkins_Skin6: return TN_MOB_CHAR6; // 4J - was L"/mob/char6.png"; case eDefaultSkins_Skin7: return TN_MOB_CHAR7; // 4J - was L"/mob/char7.png"; default: return TN_MOB_CHAR; // 4J - was L"/mob/char.png"; } } int Player::hash_fnct(const shared_ptr k) { // TODO 4J Stu - Should we just be using the pointers and hashing them? #ifdef __PS3__ return (int)boost::hash_value( k->name ); // 4J Stu - Names are completely unique? #else return (int)std::hash_value( k->name ); // 4J Stu - Names are completely unique? #endif //__PS3__ } bool Player::eq_test(const shared_ptr x, const shared_ptr y) { // TODO 4J Stu - Should we just be using the pointers and comparing them for equality? return x->name.compare( y->name ) == 0; // 4J Stu - Names are completely unique? } unsigned int Player::getPlayerGamePrivilege(EPlayerGamePrivileges privilege) { return Player::getPlayerGamePrivilege(m_uiGamePrivileges,privilege); } unsigned int Player::getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlayerGamePrivileges privilege) { if( privilege == ePlayerGamePrivilege_All ) { return uiGamePrivileges; } else if (privilege < ePlayerGamePrivilege_MAX ) { return uiGamePrivileges&(1<id) { case Tile::door_wood_Id: case Tile::button_stone_Id: case Tile::button_wood_Id: case Tile::lever_Id: case Tile::fenceGate_Id: case Tile::trapdoor_Id: allowed = true; break; } } if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) != 0) { switch(tile->id) { case Tile::chest_Id: case Tile::furnace_Id: case Tile::furnace_lit_Id: case Tile::dispenser_Id: case Tile::brewingStand_Id: case Tile::enchantTable_Id: case Tile::workBench_Id: case Tile::anvil_Id: case Tile::enderChest_Id: allowed = true; break; } } if(!allowed && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) == 0) { switch(tile->id) { case Tile::door_wood_Id: case Tile::button_stone_Id: case Tile::button_wood_Id: case Tile::lever_Id: case Tile::fenceGate_Id: case Tile::trapdoor_Id: case Tile::chest_Id: case Tile::furnace_Id: case Tile::furnace_lit_Id: case Tile::dispenser_Id: case Tile::brewingStand_Id: case Tile::enchantTable_Id: case Tile::workBench_Id: case Tile::anvil_Id: case Tile::enderChest_Id: allowed = false; break; default: allowed = true; break; } } } return allowed; } bool Player::isAllowedToUse(shared_ptr item) { bool allowed = true; if(item != NULL && app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) { if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) { allowed = false; } // 4J Stu - TU8 Players should always be able to eat food items, even if the build option is turned of switch(item->id) { // food case Item::mushroomStew_Id: case Item::apple_Id: case Item::bread_Id: case Item::porkChop_raw_Id: case Item::porkChop_cooked_Id: case Item::apple_gold_Id: case Item::fish_raw_Id: case Item::fish_cooked_Id: case Item::cookie_Id: case Item::beef_cooked_Id: case Item::beef_raw_Id: case Item::chicken_cooked_Id: case Item::chicken_raw_Id: case Item::melon_Id: case Item::rotten_flesh_Id: // bow case Item::bow_Id: case Item::sword_diamond_Id: case Item::sword_gold_Id: case Item::sword_iron_Id: case Item::sword_stone_Id: case Item::sword_wood_Id: allowed = true; break; } } return allowed; } bool Player::isAllowedToInteract(shared_ptr target) { bool allowed = true; if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) { if (target->GetType() == eTYPE_MINECART) { if (getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) == 0) { shared_ptr minecart = dynamic_pointer_cast( target ); if (minecart->type == Minecart::CHEST) allowed = false; } } else { if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) != 0) { allowed = false; } if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotMine) != 0) { allowed = false; } } } return allowed; } bool Player::isAllowedToMine() { bool allowed = true; if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) { if(getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotMine) != 0) { allowed = false; } } return allowed; } bool Player::isAllowedToAttackPlayers() { bool allowed = true; if( hasInvisiblePrivilege() || ((app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotAttackPlayers)) ) { allowed = false; } return allowed; } bool Player::isAllowedToAttackAnimals() { bool allowed = true; if( (app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotAttackAnimals) ) { allowed = false; } return allowed; } bool Player::isAllowedToHurtEntity(shared_ptr target) { bool allowed = true; if(!isAllowedToMine()) { switch(target->GetType()) { case eTYPE_HANGING_ENTITY: case eTYPE_PAINTING: case eTYPE_ITEM_FRAME: // 4J-JEV: Fix for #88212, // Untrusted players shouldn't be able to damage minecarts or boats. case eTYPE_BOAT: case eTYPE_MINECART: allowed = false; break; }; } return allowed; } bool Player::isAllowedToFly() { bool allowed = false; if(app.GetGameHostOption(eGameHostOption_HostCanFly) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanFly) != 0) { allowed = true; } return allowed; } bool Player::isAllowedToIgnoreExhaustion() { bool allowed = false; if( (app.GetGameHostOption(eGameHostOption_HostCanChangeHunger) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_ClassicHunger) != 0) || (isAllowedToFly() && abilities.flying) ) { allowed = true; } return allowed; } bool Player::isAllowedToTeleport() { bool allowed = false; if( isModerator() && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanTeleport) != 0) { allowed = true; } return allowed; } bool Player::hasInvisiblePrivilege() { bool enabled = false; if(app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Invisible) != 0) { enabled = true; } return enabled; } bool Player::hasInvulnerablePrivilege() { bool enabled = false; if(app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) != 0 && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Invulnerable) != 0) { enabled = true; } return enabled; } bool Player::isModerator() { return getPlayerGamePrivilege(Player::ePlayerGamePrivilege_Op) != 0; } void Player::enableAllPlayerPrivileges(unsigned int &uigamePrivileges, bool enable) { Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotMine, enable?0:1); Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotBuild, enable?0:1); Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotAttackPlayers, enable?0:1); Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CannotAttackAnimals, enable?0:1); Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches, enable?1:0); Player::setPlayerGamePrivilege(uigamePrivileges, Player::ePlayerGamePrivilege_CanUseContainers, enable?1:0); } void Player::enableAllPlayerPrivileges(bool enable) { Player::enableAllPlayerPrivileges(m_uiGamePrivileges,enable); } bool Player::canCreateParticles() { return !hasInvisiblePrivilege(); } vector *Player::GetAdditionalModelParts() { if(m_ppAdditionalModelParts==NULL && !m_bCheckedForModelParts) { bool hasCustomTexture = !customTextureUrl.empty(); bool customTextureIsDefaultSkin = customTextureUrl.substr(0,3).compare(L"def") == 0; // see if we can find the parts m_ppAdditionalModelParts=app.GetAdditionalModelParts(m_dwSkinId); // 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 if(!hasCustomTexture || customTextureIsDefaultSkin || m_ppAdditionalModelParts != NULL || app.IsFileInMemoryTextures(customTextureUrl)) { m_bCheckedForModelParts=true; } if(m_ppAdditionalModelParts == NULL && !m_bCheckedDLCForModelParts) { m_bCheckedDLCForModelParts = true; // we don't have the data from the dlc skin yet app.DebugPrintf("m_bCheckedForModelParts Couldn't get model parts for skin %X\n",m_dwSkinId); // do we have it from the DLC pack? DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(this->customTextureUrl); if(pDLCSkinFile!=NULL) { DWORD dwBoxC=pDLCSkinFile->getAdditionalBoxesCount(); if(dwBoxC!=0) { app.DebugPrintf("m_bCheckedForModelParts Got model parts from DLCskin for skin %X\n",m_dwSkinId); m_ppAdditionalModelParts=app.SetAdditionalSkinBoxes(m_dwSkinId,pDLCSkinFile->getAdditionalBoxes()); } app.SetAnimOverrideBitmask(pDLCSkinFile->getSkinID(),pDLCSkinFile->getAnimOverrideBitmask()); m_bCheckedForModelParts=true; } } if(m_bCheckedForModelParts) setAnimOverrideBitmask(getSkinAnimOverrideBitmask(m_dwSkinId)); } return m_ppAdditionalModelParts; } void Player::SetAdditionalModelParts(vector *ppAdditionalModelParts) { m_ppAdditionalModelParts=ppAdditionalModelParts; } #if defined(__PS3__) Player::ePlayerNameValidState Player::GetPlayerNameValidState(void) { return m_ePlayerNameValidState; } void Player::SetPlayerNameValidState(bool bState) { if(bState) { m_ePlayerNameValidState=ePlayerNameValid_True; } else { m_ePlayerNameValidState=ePlayerNameValid_False; } } #endif