From d8d65bcd49765d963b7597ddad83c1c12840cb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl?= <60509176+Bakoubak@users.noreply.github.com> Date: Sun, 4 Oct 2026 20:54:24 +0200 Subject: [PATCH] game loop: Refactor the tooltips loop Moved the whole logic to a new file (TooltipManager.cpp), and rewrote most of the logic to profit from object oriented programming. The side-effect is that the changes are scattered across entities, tiles and items because moving everything to OOP requires to add the tooltip to every .cpp file for every tile/item/entities (or their class, on plants for example which all use the tooltip IDS_TOOLTIPS_PLANT) The issue with the default tooltips loop written by 4J is that: Its running in the main Minecraft::tick loop and is more than a thousand lines long, polluting the function. Not using C++'s full potential with object oriented programming, 4J decided to use a big switch case (probably because it could run better on hardware without branch prediction like the WiiU or Xbox 360 ?) And seems to be better off in its own file than in the main Minecraft.cpp file --- Minecraft.Client/Minecraft.cpp | 1173 +----- Minecraft.Client/TooltipManager.cpp | 232 ++ Minecraft.Client/TooltipManager.h | 18 + Minecraft.Client/cmake/sources/Common.cmake | 8 +- Minecraft.Server/cmake/sources/Common.cmake | 8 +- Minecraft.World/AnvilTile.cpp | 7 +- Minecraft.World/AnvilTile.h | 3 +- Minecraft.World/BaseEntityTile.cpp | 7 +- Minecraft.World/BaseEntityTile.h | 3 +- Minecraft.World/BedTile.cpp | 7 +- Minecraft.World/BedTile.h | 2 + Minecraft.World/Boat.cpp | 19 +- Minecraft.World/Boat.h | 5 + Minecraft.World/BoatItem.cpp | 10 +- Minecraft.World/BoatItem.h | 4 +- Minecraft.World/BottleItem.cpp | 10 +- Minecraft.World/BottleItem.h | 4 +- Minecraft.World/BowItem.cpp | 17 +- Minecraft.World/BowItem.h | 4 +- Minecraft.World/BucketItem.cpp | 33 +- Minecraft.World/BucketItem.h | 4 +- Minecraft.World/Bush.cpp | 5 + Minecraft.World/Bush.h | 2 + Minecraft.World/ButtonTile.cpp | 7 +- Minecraft.World/ButtonTile.h | 4 +- Minecraft.World/CakeTile.cpp | 5 + Minecraft.World/CakeTile.h | 4 +- Minecraft.World/CauldronTile.cpp | 9 +- Minecraft.World/CauldronTile.h | 2 + Minecraft.World/ChestTile.cpp | 11 +- Minecraft.World/ChestTile.h | 3 +- Minecraft.World/Chicken.cpp | 68 +- Minecraft.World/Chicken.h | 11 +- Minecraft.World/Cow.cpp | 71 +- Minecraft.World/Cow.h | 4 + Minecraft.World/DiodeTile.cpp | 5 + Minecraft.World/DiodeTile.h | 4 +- Minecraft.World/DoorTile.cpp | 7 +- Minecraft.World/DoorTile.h | 1 + Minecraft.World/DropperTile.cpp | 7 +- Minecraft.World/DropperTile.h | 3 +- Minecraft.World/DyePowderItem.cpp | 88 +- Minecraft.World/DyePowderItem.h | 2 + Minecraft.World/EggItem.cpp | 7 +- Minecraft.World/EggItem.h | 2 + Minecraft.World/EmptyMapItem.cpp | 7 +- Minecraft.World/EmptyMapItem.h | 4 +- Minecraft.World/EnderChestTile.cpp | 5 + Minecraft.World/EnderChestTile.h | 1 + Minecraft.World/EnderDragon.cpp | 35 +- Minecraft.World/EnderDragon.h | 11 +- Minecraft.World/EnderEyeItem.cpp | 18 +- Minecraft.World/EnderEyeItem.h | 4 +- Minecraft.World/EnderpearlItem.cpp | 14 +- Minecraft.World/EnderpearlItem.h | 4 +- Minecraft.World/Entity.cpp | 10 +- Minecraft.World/Entity.h | 7 + Minecraft.World/EntityHorse.cpp | 109 +- Minecraft.World/EntityHorse.h | 9 +- Minecraft.World/ExperienceItem.cpp | 12 +- Minecraft.World/ExperienceItem.h | 4 +- Minecraft.World/FenceGateTile.cpp | 7 +- Minecraft.World/FenceGateTile.h | 1 + Minecraft.World/FireChargeItem.cpp | 21 +- Minecraft.World/FireChargeItem.h | 4 +- Minecraft.World/FireworksItem.cpp | 14 + Minecraft.World/FireworksItem.h | 6 + Minecraft.World/FishingRodItem.cpp | 17 +- Minecraft.World/FishingRodItem.h | 2 + Minecraft.World/FlintAndSteelItem.cpp | 20 +- Minecraft.World/FlintAndSteelItem.h | 2 + Minecraft.World/FlowerPotTile.cpp | 13 + Minecraft.World/FlowerPotTile.h | 2 + Minecraft.World/FoodItem.cpp | 12 +- Minecraft.World/FoodItem.h | 5 +- Minecraft.World/HangingEntityItem.cpp | 38 +- Minecraft.World/HangingEntityItem.h | 8 +- Minecraft.World/HoeItem.cpp | 17 + Minecraft.World/HoeItem.h | 4 +- Minecraft.World/HopperTile.cpp | 7 +- Minecraft.World/HopperTile.h | 3 +- Minecraft.World/Item.h | 10 +- Minecraft.World/ItemFrame.cpp | 71 +- Minecraft.World/ItemFrame.h | 7 +- Minecraft.World/JukeboxTile.cpp | 31 +- Minecraft.World/JukeboxTile.h | 2 + Minecraft.World/LeashFenceKnotEntity.cpp | 22 +- Minecraft.World/LeashFenceKnotEntity.h | 8 +- Minecraft.World/LeashItem.cpp | 26 +- Minecraft.World/LeashItem.h | 6 + Minecraft.World/LeverTile.cpp | 5 + Minecraft.World/LeverTile.h | 1 + Minecraft.World/MilkBucketItem.cpp | 7 +- Minecraft.World/MilkBucketItem.h | 3 +- Minecraft.World/Minecart.cpp | 14 +- Minecraft.World/Minecart.h | 5 + Minecraft.World/MinecartChest.cpp | 14 +- Minecraft.World/MinecartChest.h | 6 +- Minecraft.World/MinecartFurnace.cpp | 34 +- Minecraft.World/MinecartFurnace.h | 6 +- Minecraft.World/MinecartHopper.cpp | 14 +- Minecraft.World/MinecartHopper.h | 6 +- Minecraft.World/MinecartSpawner.cpp | 14 +- Minecraft.World/MinecartSpawner.h | 6 +- Minecraft.World/MinecartTNT.cpp | 14 +- Minecraft.World/MinecartTNT.h | 6 +- Minecraft.World/Mob.cpp | 32 +- Minecraft.World/Mob.h | 5 +- Minecraft.World/Mushroom.cpp | 2 +- Minecraft.World/MushroomCow.cpp | 59 +- Minecraft.World/MushroomCow.h | 6 +- Minecraft.World/NoteBlockTile.cpp | 14 + Minecraft.World/NoteBlockTile.h | 7 +- Minecraft.World/Ocelot.cpp | 80 +- Minecraft.World/Ocelot.h | 7 +- Minecraft.World/Pig.cpp | 91 +- Minecraft.World/Pig.h | 4 + Minecraft.World/Player.cpp | 50 +- Minecraft.World/Player.cpp.orig | 3542 +++++++++++++++++++ Minecraft.World/Player.h | 16 +- Minecraft.World/PotionItem.cpp | 19 +- Minecraft.World/PotionItem.h | 4 +- Minecraft.World/RailTile.cpp | 5 + Minecraft.World/RailTile.h | 4 +- Minecraft.World/RedStoneOreTile.cpp | 5 + Minecraft.World/RedStoneOreTile.h | 2 + Minecraft.World/SeedItem.cpp | 18 +- Minecraft.World/SeedItem.h | 6 +- Minecraft.World/Sheep.cpp | 111 +- Minecraft.World/Sheep.h | 4 + Minecraft.World/SnowballItem.cpp | 7 +- Minecraft.World/SnowballItem.h | 5 +- Minecraft.World/Tile.h | 22 + Minecraft.World/TileItem.cpp | 42 +- Minecraft.World/TileItem.h | 12 +- Minecraft.World/TrapDoorTile.cpp | 7 +- Minecraft.World/TrapDoorTile.h | 4 +- Minecraft.World/Villager.cpp | 17 +- Minecraft.World/Villager.h | 7 +- Minecraft.World/WaterLilyTileItem.cpp | 18 +- Minecraft.World/WaterLilyTileItem.h | 2 + Minecraft.World/WeaponItem.cpp | 11 +- Minecraft.World/WeaponItem.h | 4 +- Minecraft.World/Wolf.cpp | 237 +- Minecraft.World/Wolf.h | 4 + Minecraft.World/WorkbenchTile.cpp | 7 +- Minecraft.World/WorkbenchTile.h | 3 +- Minecraft.World/Zombie.cpp | 31 +- Minecraft.World/Zombie.h | 4 + cmake/ClientSources.cmake | 500 +++ 150 files changed, 6215 insertions(+), 1527 deletions(-) create mode 100644 Minecraft.Client/TooltipManager.cpp create mode 100644 Minecraft.Client/TooltipManager.h create mode 100644 Minecraft.World/Player.cpp.orig create mode 100644 cmake/ClientSources.cmake diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 308d46a8..31fc42c5 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -66,6 +66,7 @@ #include "../Minecraft.World/SparseDataStorage.h" #include "../Minecraft.World/ChestTileEntity.h" #include "TextureManager.h" +#include "TooltipManager.h" #ifdef _XBOX #include "Xbox/Network/NetworkPlayerXbox.h" #endif @@ -2465,1170 +2466,53 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) iX=IDS_CONTROLS_CRAFTING; } // control scheme remapping can move the Action button, so we need to check this - int *piAction; - int *piJump; - int *piUse; - int *piAlt; + int *piAction = nullptr; + int *piJump = nullptr; + int *piUse = nullptr; + int *piAlt = nullptr; - unsigned int uiAction = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_ACTION ); - unsigned int uiJump = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_JUMP ); - unsigned int uiUse = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_USE ); - unsigned int uiAlt = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_SNEAK_TOGGLE ); + unsigned int uiAction = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad), MINECRAFT_ACTION_ACTION); + unsigned int uiJump = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad), MINECRAFT_ACTION_JUMP); + unsigned int uiUse = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad), MINECRAFT_ACTION_USE); + unsigned int uiAlt = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad), MINECRAFT_ACTION_SNEAK_TOGGLE); - // Also need to handle PS3 having swapped triggers/bumpers switch(uiAction) { - case _360_JOY_BUTTON_RT: - piAction=&iRT; - break; - case _360_JOY_BUTTON_LT: - piAction=&iLT; - break; - case _360_JOY_BUTTON_LB: - piAction=&iLB; - break; - case _360_JOY_BUTTON_RB: - piAction=&iRB; - break; + case _360_JOY_BUTTON_RT: piAction = &iRT; break; + case _360_JOY_BUTTON_LT: piAction = &iLT; break; + case _360_JOY_BUTTON_LB: piAction = &iLB; break; + case _360_JOY_BUTTON_RB: piAction = &iRB; break; case _360_JOY_BUTTON_A: - default: - piAction=&iA; - break; + default: piAction = &iA; break; } switch(uiJump) { - case _360_JOY_BUTTON_LT: - piJump=&iLT; - break; - case _360_JOY_BUTTON_RT: - piJump=&iRT; - break; - case _360_JOY_BUTTON_LB: - piJump=&iLB; - break; - case _360_JOY_BUTTON_RB: - piJump=&iRB; - break; + case _360_JOY_BUTTON_LT: piJump = &iLT; break; + case _360_JOY_BUTTON_RT: piJump = &iRT; break; + case _360_JOY_BUTTON_LB: piJump = &iLB; break; + case _360_JOY_BUTTON_RB: piJump = &iRB; break; case _360_JOY_BUTTON_A: - default: - piJump=&iA; - break; + default: piJump = &iA; break; } switch(uiUse) { - case _360_JOY_BUTTON_LB: - piUse=&iLB; - break; - case _360_JOY_BUTTON_RB: - piUse=&iRB; - break; - case _360_JOY_BUTTON_LT: - piUse=&iLT; - break; + case _360_JOY_BUTTON_LB: piUse = &iLB; break; + case _360_JOY_BUTTON_RB: piUse = &iRB; break; + case _360_JOY_BUTTON_LT: piUse = &iLT; break; case _360_JOY_BUTTON_RT: - default: - piUse=&iRT; - break; + default: piUse = &iRT; break; } switch(uiAlt) { default: - case _360_JOY_BUTTON_LSTICK_RIGHT: - piAlt=&iRS; - break; - - //TODO + case _360_JOY_BUTTON_LSTICK_RIGHT: piAlt = &iRS; break; } - if (player->isUnderLiquid(Material::water)) - { - *piJump=IDS_TOOLTIPS_SWIMUP; - } - else - { - *piJump=-1; - } - - *piUse=-1; - *piAction=-1; - *piAlt=-1; - - // 4J-PB another special case for when the player is sleeping in a bed - if (player->isSleeping() && (level != nullptr) && level->isClientSide) - { - *piUse=IDS_TOOLTIPS_WAKEUP; - } - else - { - if (player->isRiding()) - { - shared_ptr mount = player->riding; - - if ( mount->instanceof(eTYPE_MINECART) || mount->instanceof(eTYPE_BOAT) ) - { - *piAlt = IDS_TOOLTIPS_EXIT; - } - else - { - *piAlt = IDS_TOOLTIPS_DISMOUNT; - } - } - - // no hit result, but we may have something in our hand that we can do something with - shared_ptr itemInstance = player->inventory->getSelected(); - - // 4J-JEV: Moved all this here to avoid having it in 3 different places. - if (itemInstance) - { - // 4J-PB - very special case for boat and empty bucket and glass bottle and more - bool bUseItem = gameMode->useItem(player, level, itemInstance, true); - - switch (itemInstance->getItem()->id) - { - // food - case Item::baked_potato_Id: - case Item::potato_Id: - case Item::pumpkin_pie_Id: - case Item::poisonous_potato_Id: - case Item::golden_carrot_Id: - case Item::carrot_Id: - case Item::mushroom_stew_Id: - case Item::apple_Id: - case Item::bread_Id: - case Item::porkchop_Id: - case Item::cooked_porkchop_Id: - case Item::golden_apple_Id: - case Item::fish_Id: - case Item::cooked_fish_Id: - case Item::cookie_Id: - case Item::cooked_beef_Id: - case Item::beef_Id: - case Item::cooked_chicken_Id: - case Item::chicken_Id: - case Item::melon_block_Id: - case Item::rotten_flesh_Id: - case Item::spider_eye_Id: - // Check that we are actually hungry so will eat this item - { - FoodItem *food = static_cast(itemInstance->getItem()); - if (food != nullptr && food->canEat(player)) - { - *piUse=IDS_TOOLTIPS_EAT; - } - } - break; - - case Item::milk_bucket_Id: - *piUse=IDS_TOOLTIPS_DRINK; - break; - - case Item::fishing_rod_Id: // use - case Item::map_Id: - *piUse=IDS_TOOLTIPS_USE; - break; - - case Item::egg_Id: // throw - case Item::snowball_Id: - *piUse=IDS_TOOLTIPS_THROW; - break; - - case Item::bow_Id: // draw or release - if ( player->abilities.instabuild || player->inventory->hasResource(Item::arrow_Id) ) - { - if (player->isUsingItem()) *piUse=IDS_TOOLTIPS_RELEASE_BOW; - else *piUse=IDS_TOOLTIPS_DRAW_BOW; - } - break; - - case Item::wooden_sword_Id: - case Item::stone_sword_Id: - case Item::iron_sword_Id: - case Item::diamond_sword_Id: - case Item::golden_sword_Id: - *piUse=IDS_TOOLTIPS_BLOCK; - break; - - case Item::bucket_Id: - case Item::glass_bottle_Id: - if (bUseItem) *piUse=IDS_TOOLTIPS_COLLECT; - break; - - case Item::lava_bucket_Id: - case Item::water_bucket_Id: - *piUse=IDS_TOOLTIPS_EMPTY; - break; - - case Item::boat_Id: - case Tile::waterlily_Id: - if (bUseItem) *piUse=IDS_TOOLTIPS_PLACE; - break; - - case Item::potion_Id: - if (bUseItem) - { - if (MACRO_POTION_IS_SPLASH(itemInstance->getAuxValue())) *piUse=IDS_TOOLTIPS_THROW; - else *piUse=IDS_TOOLTIPS_DRINK; - } - break; - - case Item::ender_pearl_Id: - if (bUseItem) *piUse=IDS_TOOLTIPS_THROW; - break; - - case Item::eye_of_ender_Id: - // This will only work if there is a stronghold in this dimension - if ( bUseItem && (level->dimension->id==0) && level->getLevelData()->getHasStronghold() ) - { - *piUse=IDS_TOOLTIPS_THROW; - } - break; - - case Item::experience_bottle_Id: - if (bUseItem) *piUse=IDS_TOOLTIPS_THROW; - break; - case Item::writable_book_Id: - *piUse = IDS_TOOLTIPS_OPEN; - break; - case Item::written_book_Id: - *piUse = IDS_TOOLTIPS_READ; - break; - case Item::leather_helmet_Id: - case Item::chainmail_helmet_Id: - case Item::iron_helmet_Id: - case Item::golden_helmet_Id: - case Item::diamond_helmet_Id: - case Item::leather_chestplate_Id: - case Item::chainmail_chestplate_Id: - case Item::iron_chestplate_Id: - case Item::golden_chestplate_Id: - case Item::diamond_chestplate_Id: - case Item::leather_leggings_Id: - case Item::chainmail_leggings_Id: - case Item::iron_leggings_Id: - case Item::golden_leggings_Id: - case Item::diamond_leggings_Id: - case Item::leather_boots_Id: - case Item::chainmail_boots_Id: - case Item::iron_boots_Id: - case Item::golden_boots_Id: - case Item::diamond_boots_Id: - *piUse = IDS_TOOLTIPS_EQUIP; - break; - } - } - - if (hitResult!=nullptr) - { - switch(hitResult->type) - { - case HitResult::TILE: - { - int x,y,z; - x=hitResult->x; - y=hitResult->y; - z=hitResult->z; - int face = hitResult->f; - - int iTileID=level->getTile(x,y ,z ); - int iData = level->getData(x, y, z); - - if( gameMode != nullptr && gameMode->getTutorial() != nullptr ) - { - // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints - gameMode->getTutorial()->onLookAt(iTileID,iData); - } - - // 4J-PB - Call the useItemOn with the TestOnly flag set - bool bUseItemOn=gameMode->useItemOn(player, level, itemInstance, x, y, z, face, hitResult->pos, true); - - /* 4J-Jev: - * Moved this here so we have item tooltips to fallback on - * for noteblocks, enderportals and flowerpots in case of non-standard items. - * (ie. ignite behaviour) - */ - if (bUseItemOn && itemInstance!=nullptr) - { - switch (itemInstance->getItem()->id) - { - case Tile::mushroom_brown_Id: - case Tile::mushroom_red_Id: - case Tile::tallgrass_Id: - case Tile::cactus_Id: - case Tile::sapling_Id: - case Tile::reeds_Id: - case Tile::yellow_flower_Id: - case Tile::red_flower_Id: - *piUse=IDS_TOOLTIPS_PLANT; - break; - - // Things to USE - case Item::wooden_hoe_Id: - case Item::stone_hoe_Id: - case Item::iron_hoe_Id: - case Item::diamond_hoe_Id: - case Item::golden_hoe_Id: - *piUse=IDS_TOOLTIPS_TILL; - break; - - case Item::wheat_seeds_Id: - case Item::netherwart_seeds_Id: - *piUse=IDS_TOOLTIPS_PLANT; - break; - - case Item::dye_Id: - // bonemeal grows various plants - if (itemInstance->getAuxValue() == DyePowderItem::WHITE) - { - switch(iTileID) - { - case Tile::sapling_Id: - case Tile::wheat_Id: - case Tile::grass_Id: - case Tile::mushroom_brown_Id: - case Tile::mushroom_red_Id: - case Tile::melon_stem_Id: - case Tile::pumpkin_stem_Id: - case Tile::carrots_Id: - case Tile::potatoes_Id: - *piUse=IDS_TOOLTIPS_GROW; - break; - } - } - break; - - case Item::painting_Id: - *piUse=IDS_TOOLTIPS_HANG; - break; - - case Item::flint_and_steel_Id: - case Item::fire_charge_Id: - *piUse=IDS_TOOLTIPS_IGNITE; - break; - - case Item::fireworks_Id: - *piUse=IDS_TOOLTIPS_FIREWORK_LAUNCH; - break; - - case Item::lead_Id: - *piUse=IDS_TOOLTIPS_ATTACH; - break; - - default: - *piUse=IDS_TOOLTIPS_PLACE; - break; - } - } - - switch(iTileID) - { - case Tile::anvil_Id: - case Tile::enchanting_table_Id: - case Tile::brewing_stand_Id: - case Tile::crafting_table_Id: - case Tile::furnace_Id: - case Tile::lit_furnace_Id: - case Tile::wooden_door_Id: - case Tile::dispenser_Id: - case Tile::lever_Id: - case Tile::stone_button_Id: - case Tile::wooden_button_Id: - case Tile::trapdoor_Id: - case Tile::fence_gate_Id: - case Tile::beacon_Id: - *piAction=IDS_TOOLTIPS_MINE; - *piUse=IDS_TOOLTIPS_USE; - break; - - case Tile::chest_Id: - *piAction = IDS_TOOLTIPS_MINE; - *piUse = (Tile::chest->getContainer(level,x,y,z) != nullptr) ? IDS_TOOLTIPS_OPEN : -1; - break; - - case Tile::ender_chest_Id: - case Tile::chest_trap_Id: - case Tile::dropper_Id: - case Tile::hopper_Id: - *piUse=IDS_TOOLTIPS_OPEN; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::activator_rail_Id: - case Tile::golden_rail_Id: - case Tile::detector_rail_Id: - case Tile::rail_Id: - if (bUseItemOn) *piUse=IDS_TOOLTIPS_PLACE; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::bed_Id: - if (bUseItemOn) *piUse=IDS_TOOLTIPS_SLEEP; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::noteblock_Id: - // if in creative mode, we will mine - if (player->abilities.instabuild) *piAction=IDS_TOOLTIPS_MINE; - else *piAction=IDS_TOOLTIPS_PLAY; - *piUse=IDS_TOOLTIPS_CHANGEPITCH; - break; - - case Tile::standing_sign_Id: - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::cauldron_Id: - // special case for a cauldron of water and an empty bottle - if (itemInstance) - { - int iID=itemInstance->getItem()->id; - int currentData = level->getData(x, y, z); - if ((iID==Item::glass_bottle_Id) && (currentData > 0)) - { - *piUse=IDS_TOOLTIPS_COLLECT; - } - } - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::cake_Id: - if (player->abilities.instabuild) // if in creative mode, we will mine - { - *piAction=IDS_TOOLTIPS_MINE; - } - else - { - if (player->getFoodData()->needsFood() ) // 4J-JEV: Changed from healthto hunger. - { - *piAction=IDS_TOOLTIPS_EAT; - *piUse=IDS_TOOLTIPS_EAT; - } - else - { - *piAction=IDS_TOOLTIPS_MINE; - } - } - break; - - case Tile::jukebox_Id: - if (!bUseItemOn && itemInstance!=nullptr) - { - int iID=itemInstance->getItem()->id; - if ( (iID>=Item::record_13_Id) && (iID<=Item::record_wait_Id) ) - { - *piUse=IDS_TOOLTIPS_PLAY; - } - *piAction=IDS_TOOLTIPS_MINE; - } - else - { - if (Tile::jukebox->TestUse(level, x, y, z, player)) // means we can eject - { - *piUse=IDS_TOOLTIPS_EJECT; - } - *piAction=IDS_TOOLTIPS_MINE; - } - break; - - case Tile::flower_pot_Id: - if ( !bUseItemOn && (itemInstance != nullptr) && (iData == 0) ) - { - int iID = itemInstance->getItem()->id; - if (iID<256) // is it a tile? - { - switch(iID) - { - case Tile::yellow_flower_Id: - case Tile::red_flower_Id: - case Tile::sapling_Id: - case Tile::mushroom_brown_Id: - case Tile::mushroom_red_Id: - case Tile::cactus_Id: - case Tile::deadbush_Id: - *piUse=IDS_TOOLTIPS_PLANT; - break; - - case Tile::tallgrass_Id: - if (itemInstance->getAuxValue() != TallGrass::TALL_GRASS) *piUse=IDS_TOOLTIPS_PLANT; - break; - } - } - } - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::unpowered_comparator_Id: - case Tile::powered_comparator_Id: - *piUse=IDS_TOOLTIPS_USE; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::unpowered_repeater_Id: - case Tile::powered_repeater_Id: - *piUse=IDS_TOOLTIPS_USE; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::redstone_ore_Id: - if (bUseItemOn) *piUse=IDS_TOOLTIPS_USE; - *piAction=IDS_TOOLTIPS_MINE; - break; - - case Tile::iron_door_Id: - if(*piUse==IDS_TOOLTIPS_PLACE) - { - *piUse = -1; - } - *piAction=IDS_TOOLTIPS_MINE; - break; - - default: - *piAction=IDS_TOOLTIPS_MINE; - break; - } - } - break; - - case HitResult::ENTITY: - eINSTANCEOF entityType = hitResult->entity->GetType(); - - if ( (gameMode != nullptr) && (gameMode->getTutorial() != nullptr) ) - { - // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints - gameMode->getTutorial()->onLookAtEntity(hitResult->entity); - } - - shared_ptr heldItem = nullptr; - if (player->inventory->IsHeldItem()) - { - heldItem = player->inventory->getSelected(); - } - int heldItemId = heldItem != nullptr ? heldItem->getItem()->id : -1; - - switch(entityType) - { - case eTYPE_CHICKEN: - { - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - shared_ptr animal = dynamic_pointer_cast(hitResult->entity); - - if (animal->isLeashed() && animal->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - break; - } - - switch(heldItemId) - { - case Item::name_tag_Id: - *piUse=IDS_TOOLTIPS_NAME; - break; - - case Item::lead_Id: - if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - break; - - default: - { - if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - break; - - case -1: break; // 4J-JEV: Empty hand. - } - } - break; - - case eTYPE_CREEPER: - { - // if currently holding flint and steel - if (heldItemId == Item::flint_and_steel_Id) - *piUse=IDS_TOOLTIPS_IGNITE; - - *piAction=IDS_TOOLTIPS_HIT; - } - break; - case eTYPE_COW: - { - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - shared_ptr animal = dynamic_pointer_cast(hitResult->entity); - - if (animal->isLeashed() && animal->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - break; - } - - switch (heldItemId) - { - // Things to USE - case Item::name_tag_Id: - *piUse=IDS_TOOLTIPS_NAME; - break; - case Item::lead_Id: - if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - break; - case Item::bucket_Id: - *piUse=IDS_TOOLTIPS_MILK; - break; - default: - { - if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - break; - - case -1: break; // 4J-JEV: Empty hand. - } - } - break; - case eTYPE_MUSHROOMCOW: - { - // 4J-PB - Fix for #13081 - No tooltip is displayed for hitting a cow when you have nothing in your hand - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - shared_ptr animal = dynamic_pointer_cast(hitResult->entity); - - if (animal->isLeashed() && animal->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - break; - } - - // It's an item - switch(heldItemId) - { - // Things to USE - case Item::name_tag_Id: - *piUse=IDS_TOOLTIPS_NAME; - break; - - case Item::lead_Id: - if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - break; - - case Item::bowl_Id: - case Item::bucket_Id: // You can milk a mooshroom with either a bowl (mushroom soup) or a bucket (milk)! - *piUse=IDS_TOOLTIPS_MILK; - break; - case Item::shears_Id: - { - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - if(!animal->isBaby()) *piUse=IDS_TOOLTIPS_SHEAR; - } - break; - default: - { - if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - break; - - case -1: break; // 4J-JEV: Empty hand. - } - } - break; - - case eTYPE_BOAT: - *piAction=IDS_TOOLTIPS_MINE; - *piUse=IDS_TOOLTIPS_SAIL; - break; - - case eTYPE_MINECART_RIDEABLE: - *piAction = IDS_TOOLTIPS_MINE; - *piUse = IDS_TOOLTIPS_RIDE; // are we in the minecart already? - 4J-JEV: Doesn't matter anymore. - break; - - case eTYPE_MINECART_FURNACE: - *piAction = IDS_TOOLTIPS_MINE; - - // if you have coal, it'll go. Is there an object in hand? - if (heldItemId == Item::coal_Id) *piUse=IDS_TOOLTIPS_USE; - break; - - case eTYPE_MINECART_CHEST: - case eTYPE_MINECART_HOPPER: - *piAction = IDS_TOOLTIPS_MINE; - *piUse = IDS_TOOLTIPS_OPEN; - break; - - case eTYPE_MINECART_SPAWNER: - case eTYPE_MINECART_TNT: - *piUse = IDS_TOOLTIPS_MINE; - break; - - case eTYPE_SHEEP: - { - // can dye a sheep - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - shared_ptr sheep = dynamic_pointer_cast(hitResult->entity); - - if (sheep->isLeashed() && sheep->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - break; - } - - switch(heldItemId) - { - case Item::name_tag_Id: - *piUse=IDS_TOOLTIPS_NAME; - break; - - case Item::lead_Id: - if (!sheep->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - break; - - case Item::dye_Id: - { - // convert to tile-based color value (0 is white instead of black) - int newColor = ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue()); - - // can only use a dye on sheep that haven't been sheared - if(!(sheep->isSheared() && sheep->getColor() != newColor)) - { - *piUse=IDS_TOOLTIPS_DYE; - } - } - break; - case Item::shears_Id: - { - // can only shear a sheep that hasn't been sheared - if ( !sheep->isBaby() && !sheep->isSheared() ) - { - *piUse=IDS_TOOLTIPS_SHEAR; - } - } - - break; - default: - { - if(!sheep->isBaby() && !sheep->isInLove() && (sheep->getAge() == 0) && sheep->isFood(heldItem)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - break; - - case -1: break; // 4J-JEV: Empty hand. - } - } - break; - - case eTYPE_PIG: - { - // can ride a pig - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - shared_ptr pig = dynamic_pointer_cast(hitResult->entity); - - if (pig->isLeashed() && pig->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - } - // 4J: fix improper tooltips for TU20 - /*else if (heldItemId == Item::lead_Id) - { - if (!pig->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - } - else if (heldItemId == Item::name_tag_Id) - { - *piUse = IDS_TOOLTIPS_NAME; - }*/ - else if (pig->hasSaddle()) // does the pig have a saddle? - { - *piUse=IDS_TOOLTIPS_MOUNT; - } - else if (!pig->isBaby()) - { - if(player->inventory->IsHeldItem()) - { - switch(heldItemId) - { - case Item::saddle_Id: - *piUse=IDS_TOOLTIPS_SADDLE; - break; - - default: - { - if (!pig->isInLove() && (pig->getAge() == 0) && pig->isFood(heldItem)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - break; - } - } - } - } - break; - - case eTYPE_WOLF: - // can be tamed, fed, and made to sit/stand, or enter love mode - { - shared_ptr wolf = dynamic_pointer_cast(hitResult->entity); - - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - if (wolf->isLeashed() && wolf->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - break; - } - - switch(heldItemId) - { - case Item::name_tag_Id: - *piUse=IDS_TOOLTIPS_NAME; - break; - - case Item::lead_Id: - if (!wolf->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - break; - - case Item::bone_Id: - if (!wolf->isAngry() && !wolf->isTame()) - { - *piUse=IDS_TOOLTIPS_TAME; - } - else if (equalsIgnoreCase(player->getUUID(), wolf->getOwnerUUID())) - { - if(wolf->isSitting()) - { - *piUse=IDS_TOOLTIPS_FOLLOWME; - } - else - { - *piUse=IDS_TOOLTIPS_SIT; - } - } - - break; - case Item::ender_pearl_Id: - // Use is throw, so don't change the tips for the wolf - break; - case Item::dye_Id: - if (wolf->isTame()) - { - if (ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue()) != wolf->getCollarColor()) - { - *piUse=IDS_TOOLTIPS_DYECOLLAR; - } - else if (wolf->isSitting()) - { - *piUse=IDS_TOOLTIPS_FOLLOWME; - } - else - { - *piUse=IDS_TOOLTIPS_SIT; - } - } - break; - default: - if(wolf->isTame()) - { - if(wolf->isFood(heldItem)) - { - if(wolf->GetSynchedHealth() < wolf->getMaxHealth()) - { - *piUse=IDS_TOOLTIPS_HEAL; - } - else - { - if(!wolf->isBaby() && !wolf->isInLove() && (wolf->getAge() == 0)) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - // break out here - break; - } - - if (equalsIgnoreCase(player->getUUID(), wolf->getOwnerUUID())) - { - if(wolf->isSitting()) - { - *piUse=IDS_TOOLTIPS_FOLLOWME; - } - else - { - *piUse=IDS_TOOLTIPS_SIT; - } - } - } - break; - } - } - break; - case eTYPE_OCELOT: - { - shared_ptr ocelot = dynamic_pointer_cast(hitResult->entity); - - if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - - if (ocelot->isLeashed() && ocelot->getLeashHolder() == player) - { - *piUse = IDS_TOOLTIPS_UNLEASH; - } - else if (heldItemId == Item::lead_Id) - { - if (!ocelot->isLeashed()) *piUse = IDS_TOOLTIPS_LEASH; - } - else if (heldItemId == Item::name_tag_Id) - { - *piUse = IDS_TOOLTIPS_NAME; - } - else if(ocelot->isTame()) - { - // 4J-PB - if you have a raw fish in your hand, you will feed the ocelot rather than have it sit/follow - if(ocelot->isFood(heldItem)) - { - if(!ocelot->isBaby()) - { - if(!ocelot->isInLove()) - { - if(ocelot->getAge() == 0) - { - *piUse=IDS_TOOLTIPS_LOVEMODE; - } - } - else - { - *piUse=IDS_TOOLTIPS_FEED; - } - } - - } - else if (equalsIgnoreCase(player->getUUID(), ocelot->getOwnerUUID()) && !ocelot->isSittingOnTile() ) - { - if(ocelot->isSitting()) - { - *piUse=IDS_TOOLTIPS_FOLLOWME; - } - else - { - *piUse=IDS_TOOLTIPS_SIT; - } - } - } - else if(heldItemId >= 0) - { - if (ocelot->isFood(heldItem)) *piUse=IDS_TOOLTIPS_TAME; - } - } - break; - - case eTYPE_PLAYER: - { - // Fix for #58576 - TU6: Content: Gameplay: Hit button prompt is available when attacking a host who has "Invisible" option turned on - shared_ptr TargetPlayer = dynamic_pointer_cast(hitResult->entity); - - if(!TargetPlayer->hasInvisiblePrivilege()) // This means they are invisible, not just that they have the privilege - { - if( app.GetGameHostOption(eGameHostOption_PvP) && player->isAllowedToAttackPlayers()) - { - *piAction=IDS_TOOLTIPS_HIT; - } - } - } - break; - - case eTYPE_ITEM_FRAME: - { - shared_ptr itemFrame = dynamic_pointer_cast(hitResult->entity); - - // is the frame occupied? - if(itemFrame->getItem()!=nullptr) - { - // rotate the item - *piUse=IDS_TOOLTIPS_ROTATE; - } - else - { - // is there an object in hand? - if(heldItemId >= 0) *piUse=IDS_TOOLTIPS_PLACE; - } - - *piAction=IDS_TOOLTIPS_HIT; - } - break; - - case eTYPE_VILLAGER: - { - // 4J-JEV: Cannot leash villagers. - - shared_ptr villager = dynamic_pointer_cast(hitResult->entity); - if (!villager->isBaby()) - { - *piUse=IDS_TOOLTIPS_TRADE; - } - *piAction=IDS_TOOLTIPS_HIT; - } - break; - - case eTYPE_ZOMBIE: - { - shared_ptr zomb = dynamic_pointer_cast(hitResult->entity); - static GoldenAppleItem *goldapple = static_cast(Item::golden_apple); - - //zomb->hasEffect(MobEffect::weakness) - not present on client. - if ( zomb->isVillager() && zomb->isWeakened() && (heldItemId == Item::golden_apple_Id) && !goldapple->isFoil(heldItem) ) - { - *piUse=IDS_TOOLTIPS_CURE; - } - *piAction=IDS_TOOLTIPS_HIT; - } - break; - - case eTYPE_HORSE: - { - shared_ptr horse = dynamic_pointer_cast(hitResult->entity); - - bool heldItemIsFood = false, heldItemIsLove = false, heldItemIsArmour = false; - - switch( heldItemId ) - { - case Item::wheat_Id: - case Item::sugar_Id: - case Item::bread_Id: - case Tile::hay_block_Id: - case Item::apple_Id: - heldItemIsFood = true; - break; - case Item::golden_carrot_Id: - case Item::golden_apple_Id: - heldItemIsLove = true; - heldItemIsFood = true; - break; - case Item::diamond_horse_armor_Id: - case Item::golden_horse_armor_Id: - case Item::iron_horse_armor_Id: - heldItemIsArmour = true; - break; - } - - if (horse->isLeashed() && horse->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - } - else if ( heldItemId == Item::lead_Id) - { - if (!horse->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - } - else if (heldItemId == Item::name_tag_Id) - { - *piUse = IDS_TOOLTIPS_NAME; - } - else if (horse->isBaby()) // 4J-JEV: Can't ride baby horses due to morals. - { - if (heldItemIsFood) - { - // 4j - Can feed foles to speed growth. - *piUse = IDS_TOOLTIPS_FEED; - } - } - else if ( !horse->isTamed() ) - { - if (heldItemId == -1) - { - // 4j - Player not holding anything, ride and attempt to break untamed horse. - *piUse = IDS_TOOLTIPS_TAME; - } - else if (heldItemIsFood) - { - // 4j - Attempt to make it like you more by feeding it. - *piUse = IDS_TOOLTIPS_FEED; - } - } - else if ( player->isSneaking() - || (heldItemId == Item::saddle_Id) - || (horse->canWearArmor() && heldItemIsArmour) - ) - { - // 4j - Access horses inventory - if (*piUse == -1) *piUse = IDS_TOOLTIPS_OPEN; - } - else if ( horse->canWearBags() - && !horse->isChestedHorse() - && (heldItemId == Tile::chest_Id) ) - { - // 4j - Attach saddle-bags (chest) to donkey or mule. - *piUse = IDS_TOOLTIPS_ATTACH; - } - else if ( horse->isReadyForParenting() - && heldItemIsLove ) - { - // 4j - Different food to mate horses. - *piUse = IDS_TOOLTIPS_LOVEMODE; - } - else if ( heldItemIsFood && (horse->getHealth() < horse->getMaxHealth()) ) - { - // 4j - Horse is damaged and can eat held item to heal - *piUse = IDS_TOOLTIPS_HEAL; - } - else - { - // 4j - Ride tamed horse. - *piUse = IDS_TOOLTIPS_MOUNT; - } - - if (player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT; - } - break; - - case eTYPE_ENDERDRAGON: - // 4J-JEV: Enderdragon cannot be named. - *piAction = IDS_TOOLTIPS_HIT; - break; - - case eTYPE_LEASHFENCEKNOT: - *piAction = IDS_TOOLTIPS_UNLEASH; - if (heldItemId == Item::lead_Id && LeashItem::bindPlayerMobsTest(player, level, player->x, player->y, player->z)) - { - *piUse = IDS_TOOLTIPS_ATTACH; - } - else - { - *piUse = IDS_TOOLTIPS_UNLEASH; - } - break; - - default: - if ( hitResult->entity->instanceof(eTYPE_MOB) ) - { - shared_ptr mob = dynamic_pointer_cast(hitResult->entity); - if (mob->isLeashed() && mob->getLeashHolder() == player) - { - *piUse=IDS_TOOLTIPS_UNLEASH; - } - else if (heldItemId == Item::lead_Id) - { - if (!mob->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH; - } - else if (heldItemId == Item::name_tag_Id) - { - *piUse=IDS_TOOLTIPS_NAME; - } - } - *piAction=IDS_TOOLTIPS_HIT; - break; - } - break; - } - } - } + // Anaël: Move the tooltips loop to TooltipManager.cpp + TooltipManager::getTooltips(player, level, hitResult, gameMode, piAction, piJump, piUse, piAlt); // 4J-JEV: Don't set tooltips when we're reloading the skin, it'll crash. if (!ui.IsReloadingSkin()) @@ -3636,7 +2520,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) int uiControlType = app.GetGameSettings(iPad, eGameSetting_ControlType); if (uiControlType == 0) { - ui.SetTooltips(iPad, iA, iB, iX, iY, iRT, iLT, iLB, iRB, iLS, iRS); // flip left and right triggers on kbm + ui.SetTooltips(iPad, iA, iB, iX, iY, iRT, iLT, iLB, iRB, iLS, iRS); // flip left and right triggers on kbm } else { @@ -4060,7 +2944,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) if((player->ullButtonsPressed&(1LL<isInputAllowed(MINECRAFT_ACTION_INVENTORY)) { if (achHeld) { - + //ui.PlayUISFX(eSFX_Press); //ui.NavigateToScene(iPad, eUIScene_AchievementsMenu); } @@ -5624,4 +4508,3 @@ int Minecraft::MustSignInReturnedPSN(void *pParam, int iPad, C4JStorage::EMessag return 0; } #endif - diff --git a/Minecraft.Client/TooltipManager.cpp b/Minecraft.Client/TooltipManager.cpp new file mode 100644 index 00000000..6f2073f1 --- /dev/null +++ b/Minecraft.Client/TooltipManager.cpp @@ -0,0 +1,232 @@ +#include "stdafx.h" +#include "../Minecraft.World/TilePos.h" +#include "../Minecraft.World/ByteBuffer.h" +#include "../Minecraft.World/ChestTileEntity.h" +#include "../Minecraft.World/Difficulty.h" +#include "../Minecraft.World/File.h" +#include "../Minecraft.World/HellRandomLevelSource.h" +#include "../Minecraft.World/IntCache.h" +#include "../Minecraft.World/Minecraft.World.h" +#include "../Minecraft.World/MobEffect.h" +#include "../Minecraft.World/SparseDataStorage.h" +#include "../Minecraft.World/SparseLightStorage.h" +#include "../Minecraft.World/StrongholdFeature.h" +#include "../Minecraft.World/System.h" +#include "../Minecraft.World/TilePos.h" +#include "../Minecraft.World/Villager.h" +#include "../Minecraft.World/net.minecraft.h" +#include "../Minecraft.World/net.minecraft.stats.h" +#include "../Minecraft.World/net.minecraft.world.entity.animal.h" +#include "../Minecraft.World/net.minecraft.world.entity.h" +#include "../Minecraft.World/net.minecraft.world.entity.item.h" +#include "../Minecraft.World/net.minecraft.world.entity.monster.h" +#include "../Minecraft.World/net.minecraft.world.entity.player.h" +#include "../Minecraft.World/net.minecraft.world.item.h" +#include "../Minecraft.World/net.minecraft.world.level.chunk.h" +#include "../Minecraft.World/net.minecraft.world.level.dimension.h" +#include "../Minecraft.World/net.minecraft.world.level.h" +#include "../Minecraft.World/net.minecraft.world.level.storage.h" +#include "../Minecraft.World/net.minecraft.world.level.tile.h" +#include "../Minecraft.World/net.minecraft.world.phys.h" +#include "AchievementPopup.h" +#include "Camera.h" +#include "Chunk.h" +#include "ClientConnection.h" +#include "Common/UI/UIScene.h" +#include "CreativeMode.h" +#include "DeathScreen.h" +#include "DemoLevel.h" +#include "DemoUser.h" +#include "EntityRenderDispatcher.h" +#include "ErrorScreen.h" +#include "FrustumCuller.h" +#include "GameMode.h" +#include "GameRenderer.h" +#include "GuiParticles.h" +#include "HumanoidModel.h" +#include "InBedChatScreen.h" +#include "Input.h" +#include "InventoryScreen.h" +#include "ItemInHandRenderer.h" +#include "LevelRenderer.h" +#include "Minecraft.h" +#include "MultiPlayerLevel.h" +#include "MultiPlayerLocalPlayer.h" +#include "Options.h" +#include "ParticleEngine.h" +#include "ProgressRenderer.h" +#include "Screen.h" +#include "StatsCounter.h" +#include "SurvivalMode.h" +#include "TextureManager.h" +#include "TexturePackRepository.h" +#include "Textures.h" +#include "TileEntityRenderDispatcher.h" +#include "Timer.h" +#include "TitleScreen.h" +#include "User.h" +#include "Windows64/Windows64_Xuid.h" +#include "stdafx.h" +#ifdef _XBOX +#include "Xbox/Network/NetworkPlayerXbox.h" +#endif +#include "Common/UI/IUIScene_CreativeMenu.h" +#include "Common/UI/UIFontData.h" +#include "DLCTexturePack.h" + +#ifdef __ORBIS__ +#include "Orbis/Network/PsPlusUpsellWrapper_Orbis.h" +#endif + +#include "TooltipManager.h" + +void TooltipManager::getTooltips(shared_ptr player, + Level *level, + HitResult *hitResult, + MultiPlayerGameMode *gameMode, + int *piAction, + int *piJump, + int *piUse, + int *piAlt) +{ + + if (piAction == nullptr || piJump == nullptr || piUse == nullptr || piAlt == nullptr) + { + return; + } + if (player == nullptr || level == nullptr) + { + return; + } + + if (player->isUnderLiquid(Material::water)) + { + *piJump = IDS_TOOLTIPS_SWIMUP; + return; + } + else + { + *piJump = -1; + } + + *piUse = -1; + *piAction = -1; + *piAlt = -1; + + // 4J-PB another special case for when the player is sleeping in a bed + if (player->isSleeping() && (level != nullptr) && level->isClientSide) + { + *piUse = IDS_TOOLTIPS_WAKEUP; + return; + } + + if (player->isRiding()) + { + shared_ptr mount = player->riding; + + if (mount->instanceof(eTYPE_MINECART) || mount->instanceof(eTYPE_BOAT)) + { + *piAlt = IDS_TOOLTIPS_EXIT; + } + else + { + *piAlt = IDS_TOOLTIPS_DISMOUNT; + } + + return; + } + + // no hit result, but we may have something in our hand that we can do something with + shared_ptr itemInstance = player->inventory->getSelected(); + + // 4J-JEV: Moved all this here to avoid having it in 3 different places. + + if (itemInstance) + { + bool bUseItem = gameMode->useItem(player, level, itemInstance, true); + + int tooltipId = itemInstance->getItem()->getUseTooltipId(itemInstance, player, level, 0, 0, 0, bUseItem); // Use 0 0 0 coordinates here because we don't need them + if (tooltipId != 0) + { + *piUse = tooltipId; + } + } + + if (hitResult != nullptr) + { + switch (hitResult->type) + { + case HitResult::TILE: + { + int x, y, z; + x = hitResult->x; + y = hitResult->y; + z = hitResult->z; + int face = hitResult->f; + + int iTileID = level->getTile(x, y, z); + int iData = level->getData(x, y, z); + + if (gameMode != nullptr && gameMode->getTutorial() != nullptr) + { + // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints + gameMode->getTutorial()->onLookAt(iTileID, iData); + } + + // 4J-PB - Call the useItemOn with the TestOnly flag set + bool bUseItemOn = gameMode->useItemOn(player, level, itemInstance, x, y, z, face, hitResult->pos, true); + + // Not4J Anaël: This is here in case of special blocks like noteblocks and ender pearls/eyes. + if (bUseItemOn && itemInstance != nullptr) + { + int tooltipId = itemInstance->getItem()->getUseTooltipId(itemInstance, player, level, x, y, z, bUseItemOn); + if (tooltipId != 0) + { + *piUse = tooltipId; + } + } + + if (iTileID > 0 && iTileID < 256 && Tile::tiles[iTileID] != nullptr) + { + Tile *pTile = Tile::tiles[iTileID]; + int interactTooltip = pTile->getInteractTooltipId(level, x, y, z, player, bUseItemOn); + if (interactTooltip != 0) + { + *piUse = interactTooltip; + } + + *piAction = pTile->getAttackTooltipId(level, x, y, z, player, bUseItemOn); + } + } + break; + + case HitResult::ENTITY: + eINSTANCEOF entityType = hitResult->entity->GetType(); + + if ((gameMode != nullptr) && (gameMode->getTutorial() != nullptr)) + { + // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints + gameMode->getTutorial()->onLookAtEntity(hitResult->entity); + } + + shared_ptr heldItem = nullptr; + if (player->inventory->IsHeldItem()) + { + heldItem = player->inventory->getSelected(); + } + int heldItemId = heldItem != nullptr ? heldItem->getItem()->id : -1; + + shared_ptr entity = hitResult->entity; + if (entity != nullptr) + { + *piAction = entity->getAttackTooltipId(player); + + int useTooltip = entity->getInteractTooltipId(level, player, heldItem); + if (useTooltip != 0) + { + *piUse = useTooltip; + } + } + } + } +} diff --git a/Minecraft.Client/TooltipManager.h b/Minecraft.Client/TooltipManager.h new file mode 100644 index 00000000..7e30b2e2 --- /dev/null +++ b/Minecraft.Client/TooltipManager.h @@ -0,0 +1,18 @@ +#pragma once +#include "stdafx.h" +#include "MultiPlayerLocalPlayer.h" +#include "../Minecraft.World/Item.h" +#include + +class TooltipManager +{ + public: + static void getTooltips(shared_ptr player, + Level *level, + HitResult *hitResult, + MultiPlayerGameMode *gameMode, + int *piAction, + int *piJump, + int *piUse, + int *piAlt); +}; diff --git a/Minecraft.Client/cmake/sources/Common.cmake b/Minecraft.Client/cmake/sources/Common.cmake index 7e695c0c..32d5257b 100644 --- a/Minecraft.Client/cmake/sources/Common.cmake +++ b/Minecraft.Client/cmake/sources/Common.cmake @@ -277,7 +277,7 @@ source_group("Common/UI" FILES ${_MINECRAFT_CLIENT_COMMON_COMMON_UI}) set(_MINECRAFT_CLIENT_COMMON_COMMON_UI_ALL_PLATFORMS "${CMAKE_CURRENT_SOURCE_DIR}/ArchiveFile.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/ArchiveFile.h" + "${CMAKE_CURRENT_SOURCE_DIR}/ArchiveFile.h" "${BASE_DIR}/UI/IUIController.h" "${BASE_DIR}/UI/IUIScene_AbstractContainerMenu.cpp" "${BASE_DIR}/UI/IUIScene_AbstractContainerMenu.h" @@ -320,8 +320,8 @@ set(_MINECRAFT_CLIENT_COMMON_COMMON_UI_ALL_PLATFORMS "${BASE_DIR}/UI/IUIScene_WritingBookMenu.cpp" "${BASE_DIR}/UI/IUIScene_WritingBookMenu.h" "${BASE_DIR}/UI/UIScene_AchievementsMenu.cpp" - "${BASE_DIR}/UI/UIScene_AchievementsMenu.h" - "${BASE_DIR}/UI/UIControl_AchievementsList.cpp" + "${BASE_DIR}/UI/UIScene_AchievementsMenu.h" + "${BASE_DIR}/UI/UIControl_AchievementsList.cpp" "${BASE_DIR}/UI/UIControl_AchievementsList.h" "${BASE_DIR}/UI/UIEnums.h" "${BASE_DIR}/UI/UIStructs.h" @@ -465,6 +465,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT "${CMAKE_CURRENT_SOURCE_DIR}/Timer.h" "${CMAKE_CURRENT_SOURCE_DIR}/User.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/User.h" + "${CMAKE_CURRENT_SOURCE_DIR}/TooltipManager.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/TooltipManager.h" ) source_group("net/minecraft/client" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT}) diff --git a/Minecraft.Server/cmake/sources/Common.cmake b/Minecraft.Server/cmake/sources/Common.cmake index 375aad5e..26642dd0 100644 --- a/Minecraft.Server/cmake/sources/Common.cmake +++ b/Minecraft.Server/cmake/sources/Common.cmake @@ -251,8 +251,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${_MS_SRC}/../Minecraft.Client/Common/UI/UIScene_TrialExitUpsell.cpp" "${_MS_SRC}/../Minecraft.Client/Common/UI/UIScene_BookAndQuillMenu.cpp" "${_MS_SRC}/../Minecraft.Client/Common/UI/UIScene_AchievementsMenu.cpp" - "${_MS_SRC}/../Minecraft.Client/Common/UI/UIScene_AchievementsMenu.h" - "${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_AchievementsList.cpp" + "${_MS_SRC}/../Minecraft.Client/Common/UI/UIScene_AchievementsMenu.h" + "${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_AchievementsList.cpp" "${_MS_SRC}/../Minecraft.Client/Common/UI/UIControl_AchievementsList.h" "${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_ClassicCraftingMenu.cpp" "${_MS_SRC}/../Minecraft.Client/Common/UI/IUIScene_ClassicCraftingMenu.h" @@ -527,7 +527,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${_MS_SRC}/../Minecraft.Client/ZombieModel.cpp" "${_MS_SRC}/../Minecraft.Client/ZombieRenderer.cpp" "${_MS_SRC}/../Minecraft.Client/GuardianModel.cpp" - "${_MS_SRC}/../Minecraft.Client/GuardianRenderer.cpp" + "${_MS_SRC}/../Minecraft.Client/GuardianRenderer.cpp" "${_MS_SRC}/../Minecraft.Client/compat_shims.cpp" "${_MS_SRC}/../Minecraft.Client/glWrapper.cpp" "${_MS_SRC}/../Minecraft.Client/iob_shim.asm" @@ -576,6 +576,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${_MS_SRC}/../Minecraft.Client/CustomHeadLayer.h" "${_MS_SRC}/../Minecraft.Client/CustomHeadLayer.cpp" "${_MS_SRC}/../Minecraft.Client/RenderLayer.h" + "${_MS_SRC}/../Minecraft.Client/TooltipManager.cpp" + "${_MS_SRC}/../Minecraft.Client/TooltipManager.h" ) source_group("" FILES ${_MINECRAFT_SERVER_COMMON_ROOT}) diff --git a/Minecraft.World/AnvilTile.cpp b/Minecraft.World/AnvilTile.cpp index 5d186c28..2756ebc0 100644 --- a/Minecraft.World/AnvilTile.cpp +++ b/Minecraft.World/AnvilTile.cpp @@ -114,4 +114,9 @@ void AnvilTile::onLand(Level *level, int xt, int yt, int zt, int data) bool AnvilTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { return true; -} \ No newline at end of file +} + +int AnvilTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/AnvilTile.h b/Minecraft.World/AnvilTile.h index 81210c14..9d47f4b7 100644 --- a/Minecraft.World/AnvilTile.h +++ b/Minecraft.World/AnvilTile.h @@ -47,4 +47,5 @@ protected: public: void onLand(Level *level, int xt, int yt, int zt, int data); bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); -}; \ No newline at end of file + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/BaseEntityTile.cpp b/Minecraft.World/BaseEntityTile.cpp index 5c8e86ea..203a759e 100644 --- a/Minecraft.World/BaseEntityTile.cpp +++ b/Minecraft.World/BaseEntityTile.cpp @@ -31,4 +31,9 @@ bool BaseEntityTile::triggerEvent(Level *level, int x, int y, int z, int b0, int return te->triggerEvent(b0, b1); } return false; -} \ No newline at end of file +} + +int BaseEntityTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/BaseEntityTile.h b/Minecraft.World/BaseEntityTile.h index 5136bab8..80c4cb31 100644 --- a/Minecraft.World/BaseEntityTile.h +++ b/Minecraft.World/BaseEntityTile.h @@ -12,4 +12,5 @@ public: virtual void onPlace(Level *level, int x, int y, int z); virtual void onRemove(Level *level, int x, int y, int z, int id, int data); virtual bool triggerEvent(Level *level, int x, int y, int z, int b0, int b1); -}; \ No newline at end of file + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/BedTile.cpp b/Minecraft.World/BedTile.cpp index 542e1419..dfa79cfd 100644 --- a/Minecraft.World/BedTile.cpp +++ b/Minecraft.World/BedTile.cpp @@ -306,8 +306,6 @@ Pos *BedTile::findStandUpPosition(Level *level, int x, int y, int z, int skipCou { int data = level->getData(x, y, z); int direction = DirectionalTile::getDirection(data); - - // try to find a clear location near the bed for (int step = 0; step <= 1; step++) { int startX = x - HEAD_DIRECTION_OFFSETS[direction][0] * step - 1; @@ -338,6 +336,11 @@ Pos *BedTile::findStandUpPosition(Level *level, int x, int y, int z, int skipCou return nullptr; } +int BedTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return bUseItemOn ? IDS_TOOLTIPS_SLEEP : 0; +} + void BedTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) { if (!isHeadPiece(data)) diff --git a/Minecraft.World/BedTile.h b/Minecraft.World/BedTile.h index 1216f9cd..3d891eb9 100644 --- a/Minecraft.World/BedTile.h +++ b/Minecraft.World/BedTile.h @@ -38,6 +38,8 @@ public: virtual int getRenderShape(); virtual bool isCubeShaped(); virtual bool isSolidRender(bool isServerLevel = false); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param virtual void neighborChanged(Level *level, int x, int y, int z, int type); virtual int getResource(int data, Random *random,int playerBonusLevel); diff --git a/Minecraft.World/Boat.cpp b/Minecraft.World/Boat.cpp index faaca25d..7d0ce205 100644 --- a/Minecraft.World/Boat.cpp +++ b/Minecraft.World/Boat.cpp @@ -332,7 +332,7 @@ void Boat::tick() { if (!level->isClientSide && !removed) { - + remove(); for (int i = 0; i < 3; i++) { @@ -342,8 +342,8 @@ void Boat::tick() { spawnAtLocation(Item::stick->id, 1, 0); } - - + + } } @@ -478,7 +478,7 @@ bool Boat::interact(shared_ptr player) if (isRiding) { - + player->xd = 0; player->yd = 0; player->zd = 0; @@ -529,3 +529,14 @@ void Boat::setDoLerp(bool doLerp) this->doLerp = doLerp; } +int Boat::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int Boat::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return IDS_TOOLTIPS_SAIL; +} diff --git a/Minecraft.World/Boat.h b/Minecraft.World/Boat.h index 5e28be2d..9921e17e 100644 --- a/Minecraft.World/Boat.h +++ b/Minecraft.World/Boat.h @@ -81,4 +81,9 @@ public: bool getDoLerp(); void setDoLerp(bool doLerp); + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/BoatItem.cpp b/Minecraft.World/BoatItem.cpp index 5ae7f744..88cfa367 100644 --- a/Minecraft.World/BoatItem.cpp +++ b/Minecraft.World/BoatItem.cpp @@ -131,4 +131,12 @@ shared_ptr BoatItem::use(shared_ptr itemInstance, Le delete hr; return itemInstance; -} \ No newline at end of file +} + +int BoatItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + return IDS_TOOLTIPS_PLACE; + + return 0; +} diff --git a/Minecraft.World/BoatItem.h b/Minecraft.World/BoatItem.h index dc78e896..af1ec8c0 100644 --- a/Minecraft.World/BoatItem.h +++ b/Minecraft.World/BoatItem.h @@ -21,4 +21,6 @@ public: * level.addEntity(new Minecart(level, x + 0.5f, y + 0.5f, z + 0.5f)); * instance.count--; return true; } return false; } */ -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/BottleItem.cpp b/Minecraft.World/BottleItem.cpp index 3e526b2a..dc674332 100644 --- a/Minecraft.World/BottleItem.cpp +++ b/Minecraft.World/BottleItem.cpp @@ -96,4 +96,12 @@ bool BottleItem::TestUse(shared_ptr itemInstance, Level *level, sh void BottleItem::registerIcons(IconRegister *iconRegister) { // We reuse another texture. -} \ No newline at end of file +} + +int BottleItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + return IDS_TOOLTIPS_COLLECT; + + return 0; +} diff --git a/Minecraft.World/BottleItem.h b/Minecraft.World/BottleItem.h index 95423c09..de8fcc81 100644 --- a/Minecraft.World/BottleItem.h +++ b/Minecraft.World/BottleItem.h @@ -17,4 +17,6 @@ public: //@Override void registerIcons(IconRegister *iconRegister); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/BowItem.cpp b/Minecraft.World/BowItem.cpp index a2d34b89..82a1ed7e 100644 --- a/Minecraft.World/BowItem.cpp +++ b/Minecraft.World/BowItem.cpp @@ -106,4 +106,19 @@ void BowItem::registerIcons(IconRegister *iconRegister) Icon *BowItem::getDrawnIcon(int amount) { return icons[amount]; -} \ No newline at end of file +} + +int BowItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (player->abilities.instabuild || player->inventory->hasResource(Item::arrow_Id)) + { + if (player->isUsingItem()) + { + return IDS_TOOLTIPS_RELEASE_BOW; + } + else + { + return IDS_TOOLTIPS_DRAW_BOW; + } + } +} diff --git a/Minecraft.World/BowItem.h b/Minecraft.World/BowItem.h index b4eba111..852445dd 100644 --- a/Minecraft.World/BowItem.h +++ b/Minecraft.World/BowItem.h @@ -28,4 +28,6 @@ public: //@Override void registerIcons(IconRegister *iconRegister); Icon *getDrawnIcon(int amount); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/BucketItem.cpp b/Minecraft.World/BucketItem.cpp index 6af2831c..d1280a27 100644 --- a/Minecraft.World/BucketItem.cpp +++ b/Minecraft.World/BucketItem.cpp @@ -43,7 +43,7 @@ bool BucketItem::TestUse(shared_ptr itemInstance, Level *level, sh } if (content == 0) - { + { if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return false; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0) { @@ -128,7 +128,7 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, } if (content == 0) - { + { if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return itemInstance; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0) { @@ -156,7 +156,7 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, { if( level->dimension->id == -1 ) player->awardStat( - GenericStats::netherLavaCollected(), + GenericStats::netherLavaCollected(), GenericStats::param_noArgs() ); @@ -208,25 +208,25 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, return itemInstance; } -bool BucketItem::emptyBucket(Level *level, int xt, int yt, int zt) +bool BucketItem::emptyBucket(Level *level, int xt, int yt, int zt) { if (content <= 0) return false; Material *material = level->getMaterial(xt, yt, zt); bool nonSolid = !material->isSolid(); - if (level->isEmptyTile(xt, yt, zt) || nonSolid) + if (level->isEmptyTile(xt, yt, zt) || nonSolid) { if (level->dimension->ultraWarm && content == Tile::flowing_water_Id) { level->playSound(xt + 0.5f, yt + 0.5f, zt + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { level->addParticle(eParticleType_largesmoke, xt + Math::random(), yt + Math::random(), zt + Math::random(), 0, 0, 0); } - } - else + } + else { if (!level->isClientSide && nonSolid && !material->isLiquid()) { @@ -240,3 +240,20 @@ bool BucketItem::emptyBucket(Level *level, int xt, int yt, int zt) return false; } + +int BucketItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (this->content == 0) // Not4J Anaël: If the bucket is empty, set the tooltip to collect + { + if(bUseItem) + { + return IDS_TOOLTIPS_COLLECT; + } + } + else + { + return IDS_TOOLTIPS_EMPTY; // Not4J Anaël: The other way arround but with a full bucket this time + } + + return 0; +} diff --git a/Minecraft.World/BucketItem.h b/Minecraft.World/BucketItem.h index 0fd90e9c..ca947110 100644 --- a/Minecraft.World/BucketItem.h +++ b/Minecraft.World/BucketItem.h @@ -17,4 +17,6 @@ public: virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); bool emptyBucket(Level *level, int xt, int yt, int zt); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/Bush.cpp b/Minecraft.World/Bush.cpp index 5575c837..1c4b68d7 100644 --- a/Minecraft.World/Bush.cpp +++ b/Minecraft.World/Bush.cpp @@ -85,3 +85,8 @@ int Bush::getRenderShape() { return Tile::SHAPE_CROSS_TEXTURE; } + +int Bush::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_PLANT; +} diff --git a/Minecraft.World/Bush.h b/Minecraft.World/Bush.h index 464fba88..ef9cfe21 100644 --- a/Minecraft.World/Bush.h +++ b/Minecraft.World/Bush.h @@ -39,4 +39,6 @@ public: virtual bool isSolidRender(bool isServerLevel = false); virtual bool isCubeShaped(); virtual int getRenderShape(); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/ButtonTile.cpp b/Minecraft.World/ButtonTile.cpp index fc030101..cfdfba62 100644 --- a/Minecraft.World/ButtonTile.cpp +++ b/Minecraft.World/ButtonTile.cpp @@ -387,4 +387,9 @@ bool ButtonTile::shouldTileTick(Level *level, int x,int y,int z) void ButtonTile::registerIcons(IconRegister *iconRegister) { // None -} \ No newline at end of file +} + +int ButtonTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/ButtonTile.h b/Minecraft.World/ButtonTile.h index 972c013a..57fee4f9 100644 --- a/Minecraft.World/ButtonTile.h +++ b/Minecraft.World/ButtonTile.h @@ -68,4 +68,6 @@ public: // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing virtual bool shouldTileTick(Level *level, int x,int y,int z); -}; \ No newline at end of file + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/CakeTile.cpp b/Minecraft.World/CakeTile.cpp index b77639cf..d824e859 100644 --- a/Minecraft.World/CakeTile.cpp +++ b/Minecraft.World/CakeTile.cpp @@ -173,4 +173,9 @@ int CakeTile::getResource(int data, Random *random, int playerBonusLevel) int CakeTile::cloneTileId(Level *level, int x, int y, int z) { return Item::cake_Id; +} + +int CakeTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return (player->abilities.instabuild == false && player->getFoodData()->needsFood()) ? IDS_TOOLTIPS_EAT : 0; } \ No newline at end of file diff --git a/Minecraft.World/CakeTile.h b/Minecraft.World/CakeTile.h index 1fe7a3fb..226272fe 100644 --- a/Minecraft.World/CakeTile.h +++ b/Minecraft.World/CakeTile.h @@ -46,4 +46,6 @@ public: virtual int convertBlockStateToLegacyData(BlockState *state) override; virtual Tile::BlockState getBlockState(LevelSource *level, int x, int y, int z) override; virtual Tile::BlockState getBlockState(int data); -}; \ No newline at end of file + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; +}; diff --git a/Minecraft.World/CauldronTile.cpp b/Minecraft.World/CauldronTile.cpp index d8b82afc..653e7bbf 100644 --- a/Minecraft.World/CauldronTile.cpp +++ b/Minecraft.World/CauldronTile.cpp @@ -122,6 +122,13 @@ bool CauldronTile::isSolidRender(bool isServerLevel) return false; } +int CauldronTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + shared_ptr item = player->inventory->getSelected(); + int currentData = level->getData(x, y, z); + return (item != nullptr && item->getItem()->id == Item::glass_bottle_Id && currentData > 0) ? IDS_TOOLTIPS_COLLECT : 0; +} + int CauldronTile::getRenderShape() { return SHAPE_CAULDRON; @@ -244,4 +251,4 @@ int CauldronTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int d int CauldronTile::getFillLevel(int data) { return data; -} \ No newline at end of file +} diff --git a/Minecraft.World/CauldronTile.h b/Minecraft.World/CauldronTile.h index 3b21a675..129637c4 100644 --- a/Minecraft.World/CauldronTile.h +++ b/Minecraft.World/CauldronTile.h @@ -39,4 +39,6 @@ public: virtual bool hasAnalogOutputSignal(); virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); static int getFillLevel(int data); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; }; diff --git a/Minecraft.World/ChestTile.cpp b/Minecraft.World/ChestTile.cpp index 6f6a991b..49114446 100644 --- a/Minecraft.World/ChestTile.cpp +++ b/Minecraft.World/ChestTile.cpp @@ -298,7 +298,7 @@ shared_ptr ChestTile::getContainer(Level *level, int x, int y, int z) if (container == nullptr) return nullptr; if (level->isSolidBlockingTile(x, y + 1, z)) return nullptr; - if (isCatSittingOnChest(level,x, y, z)) return nullptr; + if (isCatSittingOnChest(level,x, y, z)) return nullptr; if (level->getTile(x - 1, y, z) == id && (level->isSolidBlockingTile(x - 1, y + 1, z) || isCatSittingOnChest(level, x - 1, y, z))) return nullptr; if (level->getTile(x + 1, y, z) == id && (level->isSolidBlockingTile(x + 1, y + 1, z) || isCatSittingOnChest(level, x + 1, y, z))) return nullptr; @@ -346,7 +346,7 @@ int ChestTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) } } -bool ChestTile::isCatSittingOnChest(Level *level, int x, int y, int z) +bool ChestTile::isCatSittingOnChest(Level *level, int x, int y, int z) { vector > *entities = level->getEntitiesOfClass(typeid(Ocelot), AABB::newTemp(x, y + 1, z, x + 1, y + 2, z + 1)); if ( entities ) @@ -375,9 +375,14 @@ int ChestTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) return AbstractContainerMenu::getRedstoneSignalFromContainer(getContainer(level, x, y, z)); } -void ChestTile::registerIcons(IconRegister *iconRegister) +void ChestTile::registerIcons(IconRegister *iconRegister) { // Register wood as the chest's icon, because it's used by the particles // when destroying the chest icon = iconRegister->registerIcon(L"planks_oak"); } + +int ChestTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return (Tile::chest->getContainer(level, x, y, z) != nullptr) ? IDS_TOOLTIPS_OPEN : -1; +} diff --git a/Minecraft.World/ChestTile.h b/Minecraft.World/ChestTile.h index 974cce04..3c369c3f 100644 --- a/Minecraft.World/ChestTile.h +++ b/Minecraft.World/ChestTile.h @@ -59,4 +59,5 @@ public: virtual bool hasAnalogOutputSignal(); virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); virtual void registerIcons(IconRegister *iconRegister); -}; \ No newline at end of file + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/Chicken.cpp b/Minecraft.World/Chicken.cpp index 30a3d2da..fe63a2a3 100644 --- a/Minecraft.World/Chicken.cpp +++ b/Minecraft.World/Chicken.cpp @@ -71,7 +71,7 @@ void Chicken::aiStep() if (!onGround && flapping < 1) flapping = 1; flapping *= 0.9; - if (!onGround && yd < 0) + if (!onGround && yd < 0) { yd *= 0.6; } @@ -80,7 +80,7 @@ void Chicken::aiStep() if (!isBaby() && !isChickenJockey) { - if (!level->isClientSide && --eggTime <= 0) + if (!level->isClientSide && --eggTime <= 0) { playSound( eSoundType_MOB_CHICKENPLOP, 1.0f, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); spawnAtLocation(Item::egg->id, 1); @@ -90,22 +90,22 @@ void Chicken::aiStep() } -void Chicken::causeFallDamage(float distance) +void Chicken::causeFallDamage(float distance) { } -int Chicken::getAmbientSound() +int Chicken::getAmbientSound() { return eSoundType_MOB_CHICKEN_AMBIENT; } -int Chicken::getHurtSound() +int Chicken::getHurtSound() { return eSoundType_MOB_CHICKEN_HURT; } -int Chicken::getDeathSound() +int Chicken::getDeathSound() { return eSoundType_MOB_CHICKEN_HURT; } @@ -115,7 +115,7 @@ void Chicken::playStepSound(int xt, int yt, int zt, int t) playSound(eSoundType_MOB_CHICKEN_STEP, 0.15f, 1); } -int Chicken::getDeathLoot() +int Chicken::getDeathLoot() { return Item::feather->id; } @@ -130,7 +130,7 @@ void Chicken::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) spawnAtLocation(Item::feather_Id, 1); } // and some meat - if (this->isOnFire()) + if (this->isOnFire()) { spawnAtLocation(Item::cooked_chicken_Id, 1); } @@ -172,3 +172,55 @@ bool Chicken::isFood(shared_ptr itemInstance) { return (itemInstance->id == Item::wheat_seeds_Id) || (itemInstance->id == Item::netherwart_seeds_Id) || (itemInstance->id == Item::melon_seeds_Id) || (itemInstance->id == Item::pumpkin_seeds_Id); } + +int Chicken::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int Chicken::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + + switch (heldItemId) + { + case Item::name_tag_Id: + return IDS_TOOLTIPS_NAME; + + case Item::lead_Id: + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + + default: + { + if (!this->isBaby() && !this->isInLove() && (this->getAge() == 0) && this->isFood(heldItem)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + break; + + case -1: + break; // 4J-JEV: Empty hand. + } + + return 0; +} diff --git a/Minecraft.World/Chicken.h b/Minecraft.World/Chicken.h index 971e86af..bc8c2195 100644 --- a/Minecraft.World/Chicken.h +++ b/Minecraft.World/Chicken.h @@ -19,7 +19,7 @@ public: int eggTime; bool isChickenJockey; -private: +private: void _init(); public: @@ -30,7 +30,7 @@ protected: void registerAttributes(); public: - virtual void aiStep(); + virtual void aiStep(); protected: virtual void causeFallDamage(float distance); @@ -40,12 +40,15 @@ protected: virtual void playStepSound(int xt, int yt, int zt, int t); virtual int getDeathLoot(); // virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); - + virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); public: virtual shared_ptr getBreedOffspring(shared_ptr target); virtual bool isFood(shared_ptr itemInstance); - + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/Cow.cpp b/Minecraft.World/Cow.cpp index 6c0d4e84..3a43af52 100644 --- a/Minecraft.World/Cow.cpp +++ b/Minecraft.World/Cow.cpp @@ -51,17 +51,17 @@ void Cow::registerAttributes() getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); } -int Cow::getAmbientSound() +int Cow::getAmbientSound() { return eSoundType_MOB_COW_AMBIENT; } -int Cow::getHurtSound() +int Cow::getHurtSound() { return eSoundType_MOB_COW_HURT; } -int Cow::getDeathSound() +int Cow::getDeathSound() { return eSoundType_MOB_COW_HURT; } @@ -71,12 +71,12 @@ void Cow::playStepSound(int xt, int yt, int zt, int t) playSound(eSoundType_MOB_COW_STEP, 0.15f, 1); } -float Cow::getSoundVolume() +float Cow::getSoundVolume() { return 1.f; } -int Cow::getDeathLoot() +int Cow::getDeathLoot() { return Item::leather->id; } @@ -106,23 +106,23 @@ void Cow::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } */ -bool Cow::mobInteract(shared_ptr player) +bool Cow::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); - if (item != nullptr && item->id == Item::bucket->id && !player->abilities.instabuild) + if (item != nullptr && item->id == Item::bucket->id && !player->abilities.instabuild) { player->awardStat(GenericStats::cowsMilked(),GenericStats::param_cowsMilked()); playSound(eSoundType_ENTITY_COW_MILK, 1.0f, 1.0f); - if (item->count-- == 0) + if (item->count-- == 0) { player->inventory->setItem(player->inventory->selected, std::make_shared(Item::milk_bucket)); - } - else if (!player->inventory->add(std::make_shared(Item::milk_bucket))) + } + else if (!player->inventory->add(std::make_shared(Item::milk_bucket))) { player->drop(std::make_shared(Item::milk_bucket)); } - + return true; } return Animal::mobInteract(player); @@ -140,3 +140,52 @@ shared_ptr Cow::getBreedOffspring(shared_ptr target) return nullptr; } } + +int Cow::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } +} + +int Cow::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + return IDS_TOOLTIPS_UNLEASH; + + switch (heldItemId) + { + case Item::name_tag_Id: + return IDS_TOOLTIPS_NAME; + + case Item::lead_Id: + if (!this->isLeashed()) + return IDS_TOOLTIPS_LEASH; + + case Item::bucket_Id: + return IDS_TOOLTIPS_MILK; + + default: + { + if (!this->isBaby() && !this->isInLove() && (this->getAge() == 0) && this->isFood(heldItem)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + break; + + case -1: + break; // 4J-JEV: Empty hand. + } + + return 0; +} diff --git a/Minecraft.World/Cow.h b/Minecraft.World/Cow.h index 3ac716f5..9946f807 100644 --- a/Minecraft.World/Cow.h +++ b/Minecraft.World/Cow.h @@ -30,4 +30,8 @@ protected: public: virtual bool mobInteract(shared_ptr player); virtual shared_ptr getBreedOffspring(shared_ptr target); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/DiodeTile.cpp b/Minecraft.World/DiodeTile.cpp index 0c88fc0a..642c8258 100644 --- a/Minecraft.World/DiodeTile.cpp +++ b/Minecraft.World/DiodeTile.cpp @@ -337,4 +337,9 @@ int DiodeTile::getTurnOffDelay(int data) bool DiodeTile::isMatching(int id) { return isSameDiode(id); +} + +int DiodeTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; } \ No newline at end of file diff --git a/Minecraft.World/DiodeTile.h b/Minecraft.World/DiodeTile.h index 16f3347b..353419d2 100644 --- a/Minecraft.World/DiodeTile.h +++ b/Minecraft.World/DiodeTile.h @@ -43,7 +43,7 @@ protected: virtual int getAlternateSignal(LevelSource *level, int x, int y, int z, int data); virtual int getAlternateSignalAt(LevelSource *level, int x, int y, int z, int facing); -public: + public: virtual bool isSignalSource(); virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); virtual void onPlace(Level *level, int x, int y, int z); @@ -75,4 +75,6 @@ protected: public: virtual bool isMatching(int id); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; }; diff --git a/Minecraft.World/DoorTile.cpp b/Minecraft.World/DoorTile.cpp index 31540b5b..38b99faa 100644 --- a/Minecraft.World/DoorTile.cpp +++ b/Minecraft.World/DoorTile.cpp @@ -437,4 +437,9 @@ bool DoorTile::use(Level *level, const BlockPos &pos, Tile::BlockState *state, s level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, pos.getX(), pos.getY(), pos.getZ(), 0); return true; -} \ No newline at end of file +} + +int DoorTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/DoorTile.h b/Minecraft.World/DoorTile.h index a532e5cd..b218fac2 100644 --- a/Minecraft.World/DoorTile.h +++ b/Minecraft.World/DoorTile.h @@ -73,4 +73,5 @@ public: void fillVirtualBlockStateProperties(Tile::BlockState *state, LevelSource *level, const BlockPos &pos); virtual bool use(Level *level, const BlockPos &pos, Tile::BlockState *state, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; }; diff --git a/Minecraft.World/DropperTile.cpp b/Minecraft.World/DropperTile.cpp index cb5a88e4..8f2e1608 100644 --- a/Minecraft.World/DropperTile.cpp +++ b/Minecraft.World/DropperTile.cpp @@ -96,4 +96,9 @@ void DropperTile::dispenseFrom(Level *level, int x, int y, int z) trap->setItem(slot, remaining); } -} \ No newline at end of file +} + +int DropperTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_OPEN; +} diff --git a/Minecraft.World/DropperTile.h b/Minecraft.World/DropperTile.h index 3dbbd0b7..6fdcd320 100644 --- a/Minecraft.World/DropperTile.h +++ b/Minecraft.World/DropperTile.h @@ -22,7 +22,8 @@ protected: public: virtual shared_ptr newTileEntity(Level *level); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; protected: virtual void dispenseFrom(Level *level, int x, int y, int z); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/DyePowderItem.cpp b/Minecraft.World/DyePowderItem.cpp index b3cf0f76..3844e930 100644 --- a/Minecraft.World/DyePowderItem.cpp +++ b/Minecraft.World/DyePowderItem.cpp @@ -21,8 +21,8 @@ DyePowderItem::DyePowderItem(int id) : Item( id ) icons = nullptr; } -const unsigned int DyePowderItem::COLOR_DESCS[] = -{ +const unsigned int DyePowderItem::COLOR_DESCS[] = +{ IDS_ITEM_DYE_POWDER_BLACK, IDS_ITEM_DYE_POWDER_RED, IDS_ITEM_DYE_POWDER_GREEN, @@ -41,8 +41,8 @@ const unsigned int DyePowderItem::COLOR_DESCS[] = IDS_ITEM_DYE_POWDER_WHITE }; -const unsigned int DyePowderItem::COLOR_USE_DESCS[] = -{ +const unsigned int DyePowderItem::COLOR_USE_DESCS[] = +{ IDS_DESC_DYE_BLACK, IDS_DESC_DYE_RED, IDS_DESC_DYE_GREEN, @@ -102,29 +102,29 @@ const int DyePowderItem::MAGENTA = 13; const int DyePowderItem::ORANGE = 14; const int DyePowderItem::WHITE = 15; -Icon *DyePowderItem::getIcon(int itemAuxValue) +Icon *DyePowderItem::getIcon(int itemAuxValue) { int colorValue = Mth::clamp(itemAuxValue, 0, 15); return icons[colorValue]; } -unsigned int DyePowderItem::getDescriptionId(shared_ptr itemInstance) +unsigned int DyePowderItem::getDescriptionId(shared_ptr itemInstance) { int colorValue = Mth::clamp(itemInstance->getAuxValue(), 0, 15); return COLOR_DESCS[colorValue]; } -unsigned int DyePowderItem::getUseDescriptionId(shared_ptr itemInstance) +unsigned int DyePowderItem::getUseDescriptionId(shared_ptr itemInstance) { return COLOR_USE_DESCS[itemInstance->getAuxValue()]; } -bool DyePowderItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +bool DyePowderItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { if (!player->mayUseItemAt(x, y, z, face, itemInstance)) return false; // 4J-PB - Adding a test only version to allow tooltips to be displayed - if (itemInstance->getAuxValue() == WHITE) + if (itemInstance->getAuxValue() == WHITE) { // bone meal is a fertilizer, so instantly grow trees and stuff #if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) @@ -173,11 +173,11 @@ bool DyePowderItem::useOn(shared_ptr itemInstance, shared_ptr itemInstance, Level *level, int x, int y, int z, bool bTestUseOnOnly, int entityId) { int tile = level->getTile(x, y, z); - if (tile == Tile::sapling_Id) + if (tile == Tile::sapling_Id) { if(!bTestUseOnOnly) - { - if (!level->isClientSide) + { + if (!level->isClientSide) { #if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) if (level->random->nextFloat() < 0.45) static_cast(Tile::sapling)->advanceTree(level, x, y, z, level->random, false, entityId); @@ -189,7 +189,7 @@ bool DyePowderItem::growCrop(shared_ptr itemInstance, Level *level } return true; } - + else if (tile == Tile::mushroom_brown_Id || tile == Tile::mushroom_red_Id) @@ -220,13 +220,13 @@ bool DyePowderItem::growCrop(shared_ptr itemInstance, Level *level } } return true; - } + } else if (tile == Tile::carrots_Id || tile == Tile::potatoes_Id) { if (level->getData(x, y, z) == 7) return false; if(!bTestUseOnOnly) { - if (!level->isClientSide) + if (!level->isClientSide) { static_cast(Tile::tiles[tile])->growCrops(level, x, y, z); itemInstance->count--; @@ -276,42 +276,42 @@ bool DyePowderItem::growCrop(shared_ptr itemInstance, Level *level } } return true; - } - else if (tile == Tile::grass_Id) + } + else if (tile == Tile::grass_Id) { if(!bTestUseOnOnly) - { - if (!level->isClientSide) + { + if (!level->isClientSide) { itemInstance->count--; - for (int j = 0; j < 128; j++) + for (int j = 0; j < 128; j++) { int xx = x; int yy = y + 1; int zz = z; - for (int i = 0; i < j / 16; i++) + for (int i = 0; i < j / 16; i++) { xx += random->nextInt(3) - 1; yy += (random->nextInt(3) - 1) * random->nextInt(3) / 2; zz += random->nextInt(3) - 1; - if (level->getTile(xx, yy - 1, zz) != Tile::grass_Id || level->isSolidBlockingTile(xx, yy, zz)) + if (level->getTile(xx, yy - 1, zz) != Tile::grass_Id || level->isSolidBlockingTile(xx, yy, zz)) { goto mainloop; } } - if (level->getTile(xx, yy, zz) == 0) + if (level->getTile(xx, yy, zz) == 0) { - if (random->nextInt(10) != 0) + if (random->nextInt(10) != 0) { if (Tile::tallgrass->canSurvive(level, xx, yy, zz)) level->setTileAndData(xx, yy, zz, Tile::tallgrass_Id, TallGrass::TALL_GRASS, Tile::UPDATE_ALL); - } - else if (random->nextInt(3) != 0) + } + else if (random->nextInt(3) != 0) { if (Tile::flower->canSurvive(level, xx, yy, zz)) level->setTileAndUpdate(xx, yy, zz, Tile::yellow_flower_Id); - } - else + } + else { if (Tile::rose->canSurvive(level, xx, yy, zz)) level->setTileAndUpdate(xx, yy, zz, Tile::red_flower_Id); } @@ -346,14 +346,14 @@ void DyePowderItem::addGrowthParticles(Level *level, int x, int y, int z, int co } } -bool DyePowderItem::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob) +bool DyePowderItem::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob) { - if (dynamic_pointer_cast( mob ) != nullptr) + if (dynamic_pointer_cast( mob ) != nullptr) { shared_ptr sheep = dynamic_pointer_cast(mob); // convert to tile-based color value (0 is white instead of black) int newColor = ColoredTile::getTileDataForItemAuxValue(itemInstance->getAuxValue()); - if (!sheep->isSheared() && sheep->getColor() != newColor) + if (!sheep->isSheared() && sheep->getColor() != newColor) { sheep->setColor(newColor); itemInstance->count--; @@ -371,4 +371,28 @@ void DyePowderItem::registerIcons(IconRegister *iconRegister) { icons[i] = iconRegister->registerIcon(getIconName() + L"_" + COLOR_TEXTURES[i]); } -} \ No newline at end of file +} + +int DyePowderItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (itemInstance->getAuxValue() == DyePowderItem::WHITE) + { + int iTileID = level->getTile(x, y, z); + + switch (iTileID) + { + case Tile::sapling_Id: + case Tile::wheat_Id: + case Tile::grass_Id: + case Tile::mushroom_brown_Id: + case Tile::mushroom_red_Id: + case Tile::melon_stem_Id: + case Tile::pumpkin_stem_Id: + case Tile::carrots_Id: + case Tile::potatoes_Id: + return IDS_TOOLTIPS_GROW; + } + } + + return 0; +} diff --git a/Minecraft.World/DyePowderItem.h b/Minecraft.World/DyePowderItem.h index 5f41479b..ddc9b64f 100644 --- a/Minecraft.World/DyePowderItem.h +++ b/Minecraft.World/DyePowderItem.h @@ -49,4 +49,6 @@ public: //@Override void registerIcons(IconRegister *iconRegister); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/EggItem.cpp b/Minecraft.World/EggItem.cpp index 3f3d123e..21afa532 100644 --- a/Minecraft.World/EggItem.cpp +++ b/Minecraft.World/EggItem.cpp @@ -19,7 +19,7 @@ EggItem::EggItem(int id) : Item( id ) maxStackSize = 16; } -shared_ptr EggItem::use(shared_ptr instance, Level *level, shared_ptr player) +shared_ptr EggItem::use(shared_ptr instance, Level *level, shared_ptr player) { if (!player->abilities.instabuild) { @@ -29,3 +29,8 @@ shared_ptr EggItem::use(shared_ptr instance, Level * if (!level->isClientSide) level->addEntity(std::make_shared(level, player)); return instance; } + +int EggItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_THROW; +} diff --git a/Minecraft.World/EggItem.h b/Minecraft.World/EggItem.h index 83f09db5..f20f5bd2 100644 --- a/Minecraft.World/EggItem.h +++ b/Minecraft.World/EggItem.h @@ -12,4 +12,6 @@ public: EggItem(int id); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/EmptyMapItem.cpp b/Minecraft.World/EmptyMapItem.cpp index 9c46938a..73790341 100644 --- a/Minecraft.World/EmptyMapItem.cpp +++ b/Minecraft.World/EmptyMapItem.cpp @@ -40,4 +40,9 @@ shared_ptr EmptyMapItem::use(shared_ptr itemInstance } return itemInstance; -} \ No newline at end of file +} + +int EmptyMapItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/EmptyMapItem.h b/Minecraft.World/EmptyMapItem.h index 825111d0..39ae92ac 100644 --- a/Minecraft.World/EmptyMapItem.h +++ b/Minecraft.World/EmptyMapItem.h @@ -8,4 +8,6 @@ public: EmptyMapItem(int id); shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/EnderChestTile.cpp b/Minecraft.World/EnderChestTile.cpp index f1b4738f..26d89986 100644 --- a/Minecraft.World/EnderChestTile.cpp +++ b/Minecraft.World/EnderChestTile.cpp @@ -115,3 +115,8 @@ void EnderChestTile::registerIcons(IconRegister *iconRegister) // particles when destroying the chest icon = iconRegister->registerIcon(L"obsidian"); } + +int EnderChestTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_OPEN; +} diff --git a/Minecraft.World/EnderChestTile.h b/Minecraft.World/EnderChestTile.h index 4c2bbcbf..c95236f2 100644 --- a/Minecraft.World/EnderChestTile.h +++ b/Minecraft.World/EnderChestTile.h @@ -26,4 +26,5 @@ public: shared_ptr newTileEntity(Level *level); void animateTick(Level *level, int xt, int yt, int zt, Random *random); virtual void registerIcons(IconRegister *iconRegister); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; }; diff --git a/Minecraft.World/EnderDragon.cpp b/Minecraft.World/EnderDragon.cpp index 80eb6e7e..ab518307 100644 --- a/Minecraft.World/EnderDragon.cpp +++ b/Minecraft.World/EnderDragon.cpp @@ -187,7 +187,7 @@ void EnderDragon::aiStep() float flap = Mth::cos(flapTime * PI * 2); float oldFlap = Mth::cos(oFlapTime * PI * 2); - if (oldFlap <= -0.3f && flap >= -0.3f) + if (oldFlap <= -0.3f && flap >= -0.3f) { level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_MOVE, 1, 0.8f + random->nextFloat() * .3f, false, 100.0f); } @@ -715,7 +715,7 @@ void EnderDragon::aiStep() if (!level->isClientSide) { double maxDist = 64.0f; - if (getSynchedAction() == e_EnderdragonAction_StrafePlayer && attackTarget != nullptr && attackTarget->distanceToSqr(shared_from_this()) < maxDist * maxDist) + if (getSynchedAction() == e_EnderdragonAction_StrafePlayer && attackTarget != nullptr && attackTarget->distanceToSqr(shared_from_this()) < maxDist * maxDist) { if (this->canSee(attackTarget)) { @@ -746,7 +746,7 @@ void EnderDragon::aiStep() level->addEntity(ie); m_fireballCharge = 0; - app.DebugPrintf("Finding new target due to having fired a fireball\n"); + app.DebugPrintf("Finding new target due to having fired a fireball\n"); if( m_currentPath != nullptr ) { while(!m_currentPath->isDone()) @@ -757,8 +757,8 @@ void EnderDragon::aiStep() newTarget = true; findNewTarget(); } - } - else + } + else { if (m_fireballCharge > 0) m_fireballCharge--; } @@ -990,7 +990,7 @@ void EnderDragon::findNewTarget() navigateToNextPathNode(); if(m_currentPath != nullptr && m_currentPath->isDone()) - { + { setSynchedAction(e_EnderdragonAction_Landing); #if PRINT_DRAGON_STATE_CHANGE_MESSAGES app.DebugPrintf("Dragon action is now: Landing\n"); @@ -1045,7 +1045,7 @@ void EnderDragon::findNewTarget() } if(m_currentPath != nullptr) delete m_currentPath; - m_currentPath = findPath(currentNodeIndex,targetNodeIndex); + m_currentPath = findPath(currentNodeIndex,targetNodeIndex); // Always skip the first node (as that's where we are already) if(m_currentPath != nullptr) m_currentPath->next(); @@ -1214,7 +1214,7 @@ void EnderDragon::tickDeath() level->addEntity(std::make_shared(level, x, y, z, newCount)); } } - if (dragonDeathTime == 1) + if (dragonDeathTime == 1) { level->globalLevelEvent(LevelEvent::SOUND_DRAGON_DEATH, static_cast(x), static_cast(y), static_cast(z), 0); } @@ -1777,7 +1777,7 @@ Path *EnderDragon::reconstruct_path(Node *from, Node *to) NodeArray nodes = NodeArray(count); n = to; nodes.data[--count] = n; - while (n->cameFrom != nullptr) + while (n->cameFrom != nullptr) { n = n->cameFrom; nodes.data[--count] = n; @@ -1787,7 +1787,7 @@ Path *EnderDragon::reconstruct_path(Node *from, Node *to) return ret; } -void EnderDragon::addAdditonalSaveData(CompoundTag *entityTag) +void EnderDragon::addAdditonalSaveData(CompoundTag *entityTag) { app.DebugPrintf("Adding EnderDragon additional save data\n"); entityTag->putShort(L"RemainingCrystals", m_remainingCrystalsCount); @@ -1796,7 +1796,7 @@ void EnderDragon::addAdditonalSaveData(CompoundTag *entityTag) Mob::addAdditonalSaveData(entityTag); } -void EnderDragon::readAdditionalSaveData(CompoundTag *tag) +void EnderDragon::readAdditionalSaveData(CompoundTag *tag) { app.DebugPrintf("Reading EnderDragon additional save data\n"); m_remainingCrystalsCount = tag->getShort(L"RemainingCrystals"); @@ -1965,3 +1965,16 @@ Vec3 *EnderDragon::getHeadLookVector(float a) } return result; } + +int EnderDragon::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_HIT; +} + +int EnderDragon::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + // Anaël: The enderdragon doesn't have any actions besides hitting (which is handled in getAttackTooltipId), so return nothing + return 0; +} diff --git a/Minecraft.World/EnderDragon.h b/Minecraft.World/EnderDragon.h index 861af9bb..9aa6c10c 100644 --- a/Minecraft.World/EnderDragon.h +++ b/Minecraft.World/EnderDragon.h @@ -16,7 +16,7 @@ public: eINSTANCEOF GetType() { return eTYPE_ENDERDRAGON; }; static Entity *create(Level *level) { return new EnderDragon(level); } -private: +private: // 4J Added for new behaviours static const int DATA_ID_SYNCHED_ACTION = 17; @@ -169,10 +169,10 @@ private: void strafeAttackTarget(); void navigateToNextPathNode(); -public: +public: virtual void addAdditonalSaveData(CompoundTag *entityTag); virtual void readAdditionalSaveData(CompoundTag *tag); - + public: void handleCrystalDestroyed(DamageSource *source); @@ -187,4 +187,9 @@ public: virtual float getHealth() { return LivingEntity::getHealth(); }; virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); }; virtual int getDimension() { return Entity::dimension; } + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/EnderEyeItem.cpp b/Minecraft.World/EnderEyeItem.cpp index 6027c368..40aaec64 100644 --- a/Minecraft.World/EnderEyeItem.cpp +++ b/Minecraft.World/EnderEyeItem.cpp @@ -158,15 +158,15 @@ bool EnderEyeItem::TestUse(shared_ptr itemInstance, Level *level, } else { -// int x,z; +// int x,z; // if(app.GetTerrainFeaturePosition(eTerrainFeature_Stronghold,&x,&z)) // { // level->getLevelData()->setXStronghold(x); // level->getLevelData()->setZStronghold(z); // level->getLevelData()->setHasStronghold(); -// +// // app.DebugPrintf("=== FOUND stronghold in terrain features list\n"); -// +// // app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_StrongholdPosition); // } // else @@ -220,4 +220,14 @@ shared_ptr EnderEyeItem::use(shared_ptr instance, Le } } return instance; -} \ No newline at end of file +} + +int EnderEyeItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && (level->dimension->id == 0) && level->getLevelData()->getHasStronghold()) + { + return IDS_TOOLTIPS_THROW; + } + + return 0; +} diff --git a/Minecraft.World/EnderEyeItem.h b/Minecraft.World/EnderEyeItem.h index cbe880d2..f49b8089 100644 --- a/Minecraft.World/EnderEyeItem.h +++ b/Minecraft.World/EnderEyeItem.h @@ -10,4 +10,6 @@ public: virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/EnderpearlItem.cpp b/Minecraft.World/EnderpearlItem.cpp index c024190b..11f6c159 100644 --- a/Minecraft.World/EnderpearlItem.cpp +++ b/Minecraft.World/EnderpearlItem.cpp @@ -26,9 +26,19 @@ shared_ptr EnderpearlItem::use(shared_ptr instance, } level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); - if (!level->isClientSide) + if (!level->isClientSide) { level->addEntity(std::make_shared(level, player)); } return instance; -} \ No newline at end of file +} + +int EnderpearlItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + { + return IDS_TOOLTIPS_THROW; + } + + return 0; +} diff --git a/Minecraft.World/EnderpearlItem.h b/Minecraft.World/EnderpearlItem.h index 973f5284..24190b11 100644 --- a/Minecraft.World/EnderpearlItem.h +++ b/Minecraft.World/EnderpearlItem.h @@ -10,4 +10,6 @@ public: virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); // 4J added virtual bool TestUse(shared_ptr instance, Level *level, shared_ptr player); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/Entity.cpp b/Minecraft.World/Entity.cpp index f47bf644..c6138890 100644 --- a/Minecraft.World/Entity.cpp +++ b/Minecraft.World/Entity.cpp @@ -2208,6 +2208,7 @@ unsigned int Entity::getAnimOverrideBitmask() return m_uiAnimOverrideBitmask; } + float Entity::getEyeHeight() { return bbHeight * 0.85f; @@ -2428,4 +2429,11 @@ void Entity::setSkinAdjustments(struct _SkinAdjustments* adj) { this->m_skinAdjustments = *adj; -} \ No newline at end of file +} + +int Entity::getInteractTooltipId(Level* level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return 0; +} diff --git a/Minecraft.World/Entity.h b/Minecraft.World/Entity.h index 3457f217..fac64a9e 100644 --- a/Minecraft.World/Entity.h +++ b/Minecraft.World/Entity.h @@ -519,4 +519,11 @@ double distanceSqrToBlockPosCenter(BlockPos* pos); void setSkinAdjustments(struct _SkinAdjustments* adj); + virtual int getInteractTooltipId(Level* level, + std::shared_ptr player, + std::shared_ptr heldItem); + virtual int getAttackTooltipId(std::shared_ptr player) const + { + return IDS_TOOLTIPS_HIT; // Not4J Anaël: Hit by default on mobs/entities + } }; diff --git a/Minecraft.World/EntityHorse.cpp b/Minecraft.World/EntityHorse.cpp index fade0fd1..fb031a7f 100644 --- a/Minecraft.World/EntityHorse.cpp +++ b/Minecraft.World/EntityHorse.cpp @@ -1848,4 +1848,111 @@ bool EntityHorse::onLadder() shared_ptr EntityHorse::getOwner() { return level->getPlayerByUUID(getOwnerName()); -} \ No newline at end of file +} + +int EntityHorse::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int EntityHorse::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + bool heldItemIsFood = false, heldItemIsLove = false, heldItemIsArmour = false; + + switch (heldItemId) + { + case Item::wheat_Id: + case Item::sugar_Id: + case Item::bread_Id: + case Tile::hay_block_Id: + case Item::apple_Id: + heldItemIsFood = true; + break; + case Item::golden_carrot_Id: + case Item::golden_apple_Id: + heldItemIsLove = true; + heldItemIsFood = true; + break; + case Item::diamond_horse_armor_Id: + case Item::golden_horse_armor_Id: + case Item::iron_horse_armor_Id: + heldItemIsArmour = true; + break; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + else if (heldItemId == Item::lead_Id) + { + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + } + else if (heldItemId == Item::name_tag_Id) + { + return IDS_TOOLTIPS_NAME; + } + else if (this->isBaby()) // 4J-JEV: Can't ride baby horses due to morals. + { + if (heldItemIsFood) + { + // 4j - Can feed foles to speed growth. + return IDS_TOOLTIPS_FEED; + } + } + else if (!this->isTamed()) + { + if (heldItemId == -1) + { + // 4j - Player not holding anything, ride and attempt to break untamed horse. + return IDS_TOOLTIPS_TAME; + } + else if (heldItemIsFood) + { + // 4j - Attempt to make it like you more by feeding it. + return IDS_TOOLTIPS_FEED; + } + } + else if (player->isSneaking() || (heldItemId == Item::saddle_Id) || (this->canWearArmor() && heldItemIsArmour)) + { + return IDS_TOOLTIPS_OPEN; + } + else if (this->canWearBags() && !this->isChestedHorse() && (heldItemId == Tile::chest_Id)) + { + // 4j - Attach saddle-bags (chest) to donkey or mule. + return IDS_TOOLTIPS_ATTACH; + } + else if (this->isReadyForParenting() && heldItemIsLove) + { + // 4j - Different food to mate horses. + return IDS_TOOLTIPS_LOVEMODE; + } + else if (heldItemIsFood && (this->getHealth() < this->getMaxHealth())) + { + // 4j - horse is damaged and can eat held item to heal + return IDS_TOOLTIPS_HEAL; + } + else + { + // 4j - Ride tamed horse. + return IDS_TOOLTIPS_MOUNT; + } + + return 0; +} diff --git a/Minecraft.World/EntityHorse.h b/Minecraft.World/EntityHorse.h index c91da172..bb1da86e 100644 --- a/Minecraft.World/EntityHorse.h +++ b/Minecraft.World/EntityHorse.h @@ -324,7 +324,7 @@ private: virtual float generateRandomMaxHealth(); virtual double generateRandomJumpStrength(); virtual double generateRandomSpeed(); - + shared_ptr getOwner(); public: @@ -340,4 +340,9 @@ public: static bool isHorseArmor(int itemId); virtual bool onLadder(); -}; \ No newline at end of file + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/ExperienceItem.cpp b/Minecraft.World/ExperienceItem.cpp index a28a5859..ed0000aa 100644 --- a/Minecraft.World/ExperienceItem.cpp +++ b/Minecraft.World/ExperienceItem.cpp @@ -29,4 +29,14 @@ shared_ptr ExperienceItem::use(shared_ptr itemInstan level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) level->addEntity(std::make_shared(level, player)); return itemInstance; -} \ No newline at end of file +} + +int ExperienceItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + { + return IDS_TOOLTIPS_THROW; + } + + return 0; +} diff --git a/Minecraft.World/ExperienceItem.h b/Minecraft.World/ExperienceItem.h index 89dac191..cef5e654 100644 --- a/Minecraft.World/ExperienceItem.h +++ b/Minecraft.World/ExperienceItem.h @@ -12,4 +12,6 @@ public: virtual bool isFoil(shared_ptr itemInstance); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/FenceGateTile.cpp b/Minecraft.World/FenceGateTile.cpp index 39584442..1e1e34cd 100644 --- a/Minecraft.World/FenceGateTile.cpp +++ b/Minecraft.World/FenceGateTile.cpp @@ -231,4 +231,9 @@ void FenceGateTile::registerIcons(IconRegister *iconRegister) bool FenceGateTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { return true; -} \ No newline at end of file +} + +int FenceGateTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/FenceGateTile.h b/Minecraft.World/FenceGateTile.h index 986b48d4..304a2c25 100644 --- a/Minecraft.World/FenceGateTile.h +++ b/Minecraft.World/FenceGateTile.h @@ -31,4 +31,5 @@ public: virtual void neighborChanged(Level *level, int x, int y, int z, int type); static bool isOpen(int data); virtual void registerIcons(IconRegister* iconRegister); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; }; diff --git a/Minecraft.World/FireChargeItem.cpp b/Minecraft.World/FireChargeItem.cpp index 586c3e08..b23e4072 100644 --- a/Minecraft.World/FireChargeItem.cpp +++ b/Minecraft.World/FireChargeItem.cpp @@ -15,7 +15,7 @@ FireChargeItem::FireChargeItem(int id) : Item(id) bool FireChargeItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { - if (level->isClientSide) + if (level->isClientSide) { return true; } @@ -27,7 +27,7 @@ bool FireChargeItem::useOn(shared_ptr instance, shared_ptr if (face == 4) x--; if (face == 5) x++; - if (!player->mayUseItemAt(x, y, z, face, instance)) + if (!player->mayUseItemAt(x, y, z, face, instance)) { return false; } @@ -40,13 +40,13 @@ bool FireChargeItem::useOn(shared_ptr instance, shared_ptr int targetType = level->getTile(x, y, z); - if (targetType == 0) + if (targetType == 0) { level->playSound( x + 0.5, y + 0.5, z + 0.5,eSoundType_FIRE_NEWIGNITE, 1, random->nextFloat() * 0.4f + 0.8f); level->setTileAndUpdate(x, y, z, Tile::fire_Id); } - if (!player->abilities.instabuild) + if (!player->abilities.instabuild) { instance->count--; } @@ -65,3 +65,16 @@ void FireChargeItem::registerIcons(IconRegister *iconRegister) m_dragonFireballIcon = iconRegister->registerIcon(L"dragonFireball"); } +int FireChargeItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level *level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + int targetType = level->getTile(x, y, z); + if (targetType != 0) + { + return IDS_TOOLTIPS_IGNITE; + } + } + + return 0; +} diff --git a/Minecraft.World/FireChargeItem.h b/Minecraft.World/FireChargeItem.h index c0890a46..1b2a294c 100644 --- a/Minecraft.World/FireChargeItem.h +++ b/Minecraft.World/FireChargeItem.h @@ -17,4 +17,6 @@ public: virtual Icon *getIcon(int itemAuxValue); virtual void registerIcons(IconRegister *iconRegister); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/FireworksItem.cpp b/Minecraft.World/FireworksItem.cpp index 79c3bf9b..0c90bad3 100644 --- a/Minecraft.World/FireworksItem.cpp +++ b/Minecraft.World/FireworksItem.cpp @@ -97,4 +97,18 @@ void FireworksItem::appendHoverText(shared_ptr itemInstance, share } } } +} + +int FireworksItem::getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const +{ + if (bUseItem) + { + return IDS_TOOLTIPS_FIREWORK_LAUNCH; + } + + return 0; } \ No newline at end of file diff --git a/Minecraft.World/FireworksItem.h b/Minecraft.World/FireworksItem.h index 20d2f9f7..8fb16682 100644 --- a/Minecraft.World/FireworksItem.h +++ b/Minecraft.World/FireworksItem.h @@ -29,4 +29,10 @@ public: bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const override; }; \ No newline at end of file diff --git a/Minecraft.World/FishingRodItem.cpp b/Minecraft.World/FishingRodItem.cpp index 95408fa5..42ea3a92 100644 --- a/Minecraft.World/FishingRodItem.cpp +++ b/Minecraft.World/FishingRodItem.cpp @@ -20,12 +20,12 @@ FishingRodItem::FishingRodItem(int id) : Item(id) emptyIcon = nullptr; } -bool FishingRodItem::isHandEquipped() +bool FishingRodItem::isHandEquipped() { return true; } -bool FishingRodItem::isMirroredArt() +bool FishingRodItem::isMirroredArt() { return true; } @@ -38,16 +38,16 @@ int FishingRodItem::getEnchantmentValue() shared_ptr FishingRodItem::use(shared_ptr instance, Level *level, shared_ptr player) { - if (player->fishing != nullptr) + if (player->fishing != nullptr) { int dmg = player->fishing->retrieve(); instance->hurtAndBreak(dmg, player); player->swing(); - } - else + } + else { level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); - if (!level->isClientSide) + if (!level->isClientSide) { // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' shared_ptr hook = std::make_shared(level, player); @@ -69,3 +69,8 @@ Icon *FishingRodItem::getEmptyIcon() { return emptyIcon; } + +int FishingRodItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/FishingRodItem.h b/Minecraft.World/FishingRodItem.h index 4a6153d5..4812d927 100644 --- a/Minecraft.World/FishingRodItem.h +++ b/Minecraft.World/FishingRodItem.h @@ -20,4 +20,6 @@ public: virtual int getEnchantmentValue(); void registerIcons(IconRegister *iconRegister); Icon *getEmptyIcon(); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/FlintAndSteelItem.cpp b/Minecraft.World/FlintAndSteelItem.cpp index 18f6bb18..aab0f9f9 100644 --- a/Minecraft.World/FlintAndSteelItem.cpp +++ b/Minecraft.World/FlintAndSteelItem.cpp @@ -15,7 +15,7 @@ FlintAndSteelItem::FlintAndSteelItem(int id) : Item( id ) setMaxDamage(64); } -bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { // 4J-PB - Adding a test only version to allow tooltips to be displayed if (face == 0) y--; @@ -24,14 +24,14 @@ bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptrmayUseItemAt(x, y, z, face, instance)) return false; int targetType = level->getTile(x, y, z); if(!bTestUseOnOnly) - { - if (targetType == 0) + { + if (targetType == 0) { if( level->getTile(x, y-1, z) == Tile::obsidian_Id ) { @@ -70,3 +70,15 @@ bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + int targetType = level->getTile(x, y, z); + if (targetType != 0) + return IDS_TOOLTIPS_IGNITE; + } + + return 0; +} diff --git a/Minecraft.World/FlintAndSteelItem.h b/Minecraft.World/FlintAndSteelItem.h index 4456330a..540326e3 100644 --- a/Minecraft.World/FlintAndSteelItem.h +++ b/Minecraft.World/FlintAndSteelItem.h @@ -11,4 +11,6 @@ public: FlintAndSteelItem(int id); virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/FlowerPotTile.cpp b/Minecraft.World/FlowerPotTile.cpp index cee49218..a51c671a 100644 --- a/Minecraft.World/FlowerPotTile.cpp +++ b/Minecraft.World/FlowerPotTile.cpp @@ -208,6 +208,19 @@ shared_ptr FlowerPotTile::getItemFromType(int type) return nullptr; } +int FlowerPotTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + if (bUseItemOn == false && level->getData(x, y, z) == 0) + { + shared_ptr item = player->inventory->getSelected(); + if (item != nullptr && getTypeFromItem(item) != 0) + { + return IDS_TOOLTIPS_PLANT; + } + } + return 0; +} + int FlowerPotTile::getTypeFromItem(shared_ptr item) { int id = item->getItem()->id; diff --git a/Minecraft.World/FlowerPotTile.h b/Minecraft.World/FlowerPotTile.h index 7094c274..40d55bc9 100644 --- a/Minecraft.World/FlowerPotTile.h +++ b/Minecraft.World/FlowerPotTile.h @@ -45,4 +45,6 @@ public: int getResource(int data, Random *random, int playerBonusLevel); static shared_ptr getItemFromType(int type); static int getTypeFromItem(shared_ptr item); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; }; \ No newline at end of file diff --git a/Minecraft.World/FoodItem.cpp b/Minecraft.World/FoodItem.cpp index 9a9affe6..a14109fe 100644 --- a/Minecraft.World/FoodItem.cpp +++ b/Minecraft.World/FoodItem.cpp @@ -114,7 +114,17 @@ FoodItem *FoodItem::setCanAlwaysEat() } // 4J Added -bool FoodItem::canEat(shared_ptr player) +bool FoodItem::canEat(shared_ptr player) const { return player->canEat(canAlwaysEat); } + +int FoodItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (player != nullptr && FoodItem::canEat(player)) + { + return IDS_TOOLTIPS_EAT; + } + + return 0; +} diff --git a/Minecraft.World/FoodItem.h b/Minecraft.World/FoodItem.h index 84408c23..3c4a5c87 100644 --- a/Minecraft.World/FoodItem.h +++ b/Minecraft.World/FoodItem.h @@ -45,5 +45,6 @@ public: FoodItem *setCanAlwaysEat(); // 4J Added - bool canEat(shared_ptr player); -}; \ No newline at end of file + bool canEat(shared_ptr player) const; + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/HangingEntityItem.cpp b/Minecraft.World/HangingEntityItem.cpp index 6a837ad5..8beb94cb 100644 --- a/Minecraft.World/HangingEntityItem.cpp +++ b/Minecraft.World/HangingEntityItem.cpp @@ -36,9 +36,9 @@ bool HangingEntityItem::useOn(shared_ptr instance, shared_ptrmayUseItemAt(xt, yt, zt, face, instance)) return false; - if (entity != nullptr && entity->survives()) + if (entity != nullptr && entity->survives()) { - if (!level->isClientSide) + if (!level->isClientSide) { if(level->addEntity(entity)==TRUE) { @@ -70,14 +70,14 @@ bool HangingEntityItem::useOn(shared_ptr instance, shared_ptr HangingEntityItem::createEntity(Level *level, int x, int y, int z, int dir, int auxValue) // 4J added auxValue { - if (eType == eTYPE_PAINTING) + if (eType == eTYPE_PAINTING) { shared_ptr painting = std::make_shared(level, x, y, z, dir); painting->placedByPlayer = true; painting->placedByTutorial = false; #ifndef _CONTENT_PACKAGE - if (app.DebugArtToolsOn() && auxValue > 0) + if (app.DebugArtToolsOn() && auxValue > 0) { painting->PaintingPostConstructor(dir, auxValue - 1); } @@ -86,10 +86,10 @@ shared_ptr HangingEntityItem::createEntity(Level *level, int x, i { painting->PaintingPostConstructor(dir); } - + return dynamic_pointer_cast (painting); - } - else if (eType == eTYPE_ITEM_FRAME) + } + else if (eType == eTYPE_ITEM_FRAME) { shared_ptr itemFrame = std::make_shared(level, x, y, z, dir); itemFrame->placedByPlayer = true; @@ -97,8 +97,8 @@ shared_ptr HangingEntityItem::createEntity(Level *level, int x, i itemFrame->setDir(dir); return dynamic_pointer_cast (itemFrame); - } - else + } + else { return nullptr; } @@ -108,10 +108,10 @@ shared_ptr HangingEntityItem::createEntity(Level *level, int x, i void HangingEntityItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) { #ifndef _CONTENT_PACKAGE - if (eType == eTYPE_PAINTING && app.DebugArtToolsOn() && itemInstance->getAuxValue() > 0 ) + if (eType == eTYPE_PAINTING && app.DebugArtToolsOn() && itemInstance->getAuxValue() > 0 ) { int motive = itemInstance->getAuxValue() - 1; - + wchar_t formatted[256]; ZeroMemory(formatted, 256 * sizeof(wchar_t)); swprintf(formatted, 256, L"** %ls %dx%d",Painting::Motive::values[motive]->name.c_str(),Painting::Motive::values[motive]->w/16,Painting::Motive::values[motive]->h/16); @@ -125,4 +125,18 @@ void HangingEntityItem::appendHoverText(shared_ptr itemInstance, s { return Item::appendHoverText(itemInstance, player, lines, advanced); } -} \ No newline at end of file +} + +int HangingEntityItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level *level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + // Not4J Anaël: We need a wall or something solid to place it or the tooltip will be wrong + if (level->isSolidBlockingTile(x, y, z)) + { + return IDS_TOOLTIPS_HANG; + } + } + + return 0; +} diff --git a/Minecraft.World/HangingEntityItem.h b/Minecraft.World/HangingEntityItem.h index 6c1a641d..00091b22 100644 --- a/Minecraft.World/HangingEntityItem.h +++ b/Minecraft.World/HangingEntityItem.h @@ -4,7 +4,7 @@ class HangingEntity; -class HangingEntityItem : public Item +class HangingEntityItem : public Item { private: //final Class clazz; @@ -13,11 +13,13 @@ private: public: HangingEntityItem(int id, eINSTANCEOF eClassType); - virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int xt, int yt, int zt, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly);//, float clickX, float clickY, float clickZ); - + virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int xt, int yt, int zt, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly);//, float clickX, float clickY, float clickZ); + private: shared_ptr createEntity(Level *level, int x, int y, int z, int dir, int auxValue); // 4J Stu added auxValue param public: virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/HoeItem.cpp b/Minecraft.World/HoeItem.cpp index 5978c10b..5fd6b523 100644 --- a/Minecraft.World/HoeItem.cpp +++ b/Minecraft.World/HoeItem.cpp @@ -54,3 +54,20 @@ const Item::Tier *HoeItem::getTier() { return tier; } + +int HoeItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + int targetType = level->getTile(x, y, z); + int above = level->getTile(x, y + 1, z); + + // Not4J Anaël: We need to check if the target block is grass, dirt or mycelium and if the top is exposed to air + if (above == 0 && (targetType == Tile::grass_Id || targetType == Tile::dirt_Id || targetType == Tile::mycelium_Id)) + { + return IDS_TOOLTIPS_TILL; + } + } + + return 0; +} diff --git a/Minecraft.World/HoeItem.h b/Minecraft.World/HoeItem.h index bb3dd370..4aed8af6 100644 --- a/Minecraft.World/HoeItem.h +++ b/Minecraft.World/HoeItem.h @@ -17,4 +17,6 @@ public: virtual float getDestroySpeed(shared_ptr itemInstance, Tile *tile) override; const Tier *getTier(); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/HopperTile.cpp b/Minecraft.World/HopperTile.cpp index 6cb54f36..ecee5843 100644 --- a/Minecraft.World/HopperTile.cpp +++ b/Minecraft.World/HopperTile.cpp @@ -234,4 +234,9 @@ wstring HopperTile::getTileItemIconName() shared_ptr HopperTile::getHopper(LevelSource *level, int x, int y, int z) { return dynamic_pointer_cast( level->getTileEntity(x, y, z) ); -} \ No newline at end of file +} + +int HopperTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_OPEN; +} diff --git a/Minecraft.World/HopperTile.h b/Minecraft.World/HopperTile.h index 2d0790ef..64928d83 100644 --- a/Minecraft.World/HopperTile.h +++ b/Minecraft.World/HopperTile.h @@ -59,4 +59,5 @@ public: static Icon *getTexture(const wstring &name); virtual wstring getTileItemIconName(); static shared_ptr getHopper(LevelSource *level, int x, int y, int z); -}; \ No newline at end of file + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/Item.h b/Minecraft.World/Item.h index 8c1a62ba..3eab1ae4 100644 --- a/Minecraft.World/Item.h +++ b/Minecraft.World/Item.h @@ -827,4 +827,12 @@ public: virtual bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); virtual void registerIcons(IconRegister *iconRegister); virtual attrAttrModMap *getDefaultAttributeModifiers(); -}; \ No newline at end of file + virtual int getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const + { + return 0; + } +}; diff --git a/Minecraft.World/ItemFrame.cpp b/Minecraft.World/ItemFrame.cpp index ea64d059..6353d2af 100644 --- a/Minecraft.World/ItemFrame.cpp +++ b/Minecraft.World/ItemFrame.cpp @@ -37,7 +37,7 @@ ItemFrame::ItemFrame(Level *level, int xTile, int yTile, int zTile, int dir) : H setDir(dir); } -void ItemFrame::defineSynchedData() +void ItemFrame::defineSynchedData() { getEntityData()->defineNULL(DATA_ITEM, nullptr); getEntityData()->define(DATA_ROTATION, static_cast(0)); @@ -50,7 +50,7 @@ bool ItemFrame::shouldRenderAtSqrDistance(double distance) return distance < size * size; } -void ItemFrame::dropItem(shared_ptr causedBy) +void ItemFrame::dropItem(shared_ptr causedBy) { shared_ptr item = getItem(); @@ -84,7 +84,7 @@ void ItemFrame::removeFramedMap(shared_ptr item) item->setFramed(nullptr); } -shared_ptr ItemFrame::getItem() +shared_ptr ItemFrame::getItem() { return getEntityData()->getItemInstance(DATA_ITEM); } @@ -128,16 +128,16 @@ void ItemFrame::setRotation(int rotation, bool notifyNeighbors) void ItemFrame::setRotation(int rotation) { - + getEntityData()->set(DATA_ROTATION, static_cast(rotation % 8)); level->updateNeighbourForOutputSignal(xTile, yTile, zTile, Tile::comparator_off->id); } -void ItemFrame::addAdditonalSaveData(CompoundTag *tag) +void ItemFrame::addAdditonalSaveData(CompoundTag *tag) { - if (getItem() != nullptr) + if (getItem() != nullptr) { tag->putCompound(L"Item", getItem()->save(new CompoundTag())); tag->putByte(L"ItemRotation", static_cast(getRotation())); @@ -146,10 +146,10 @@ void ItemFrame::addAdditonalSaveData(CompoundTag *tag) HangingEntity::addAdditonalSaveData(tag); } -void ItemFrame::readAdditionalSaveData(CompoundTag *tag) +void ItemFrame::readAdditionalSaveData(CompoundTag *tag) { CompoundTag *itemTag = tag->getCompound(L"Item"); - if (itemTag != nullptr && !itemTag->isEmpty()) + if (itemTag != nullptr && !itemTag->isEmpty()) { setItem(ItemInstance::fromTag(itemTag)); setRotation(tag->getByte(L"ItemRotation")); @@ -159,37 +159,37 @@ void ItemFrame::readAdditionalSaveData(CompoundTag *tag) HangingEntity::readAdditionalSaveData(tag); } -bool ItemFrame::interact(shared_ptr player) +bool ItemFrame::interact(shared_ptr player) { if(!player->isAllowedToInteract(shared_from_this())) { return false; } - if (getItem() == nullptr) + if (getItem() == nullptr) { shared_ptr item = player->getCarriedItem(); - if (item != nullptr) + if (item != nullptr) { - if (!level->isClientSide)//isClientSide) + if (!level->isClientSide)//isClientSide) { setItem(item); playSound(eSoundType_ENTITY_ITEMFRAME_ADD_ITEM, 1.0f, 1.0f); - if (!player->abilities.instabuild) + if (!player->abilities.instabuild) { - if (--item->count <= 0) + if (--item->count <= 0) { player->inventory->setItem(player->inventory->selected, nullptr); } } } } - } - else + } + else { - if (!level->isClientSide)//isClientSide) + if (!level->isClientSide)//isClientSide) { setRotation(getRotation() + 1); playSound(eSoundType_ENTITY_ITEMFRAME_ROTATE_ITEM, 1.0f, 1.0f); @@ -204,11 +204,11 @@ bool ItemFrame::hurt(DamageSource *source, float damage) if (level->isClientSide) return false; shared_ptr item = getItem(); - + if (!source->isExplosion() && item != nullptr) { shared_ptr sourceEntity = source->getEntity(); - + if (sourceEntity != nullptr && sourceEntity->instanceof(eTYPE_PLAYER)) { shared_ptr player = dynamic_pointer_cast(sourceEntity); @@ -250,4 +250,35 @@ int ItemFrame::getAnalogOutput() float ItemFrame::getPickRadius() { return 0.0f; -} \ No newline at end of file +} + +int ItemFrame::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_HIT; +} + +int ItemFrame::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + // is the frame occupied? + if (this->getItem() != nullptr) + { + // rotate the item + return IDS_TOOLTIPS_ROTATE; + } + else + { + // is there an object in hand? + if (heldItemId >= 0) + { + return IDS_TOOLTIPS_PLACE; + } + } +} diff --git a/Minecraft.World/ItemFrame.h b/Minecraft.World/ItemFrame.h index dc83505f..4f185fcc 100644 --- a/Minecraft.World/ItemFrame.h +++ b/Minecraft.World/ItemFrame.h @@ -50,4 +50,9 @@ public: virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); virtual bool interact(shared_ptr player); -}; \ No newline at end of file + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/JukeboxTile.cpp b/Minecraft.World/JukeboxTile.cpp index db6f993d..3f0a589d 100644 --- a/Minecraft.World/JukeboxTile.cpp +++ b/Minecraft.World/JukeboxTile.cpp @@ -5,6 +5,7 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.h" #include "net.minecraft.world.h" +#include "net.minecraft.world.entity.player.h" #include "JukeboxTile.h" #include "LevelEvent.h" @@ -190,4 +191,32 @@ int JukeboxTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int di { shared_ptr record = dynamic_pointer_cast( level->getTileEntity(x, y, z))->getRecord(); return record == nullptr ? Redstone::SIGNAL_NONE : record->id + 1 - Item::record_13_Id; -} \ No newline at end of file +} + +int JukeboxTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + shared_ptr item = player->inventory->IsHeldItem() ? player->inventory->getSelected() : nullptr; + + // Not4J Anaël: We need to check if the player holds a disk before displaying the tooltip + if (item != nullptr && item->getItem() != nullptr) + { + int itemId = item->getItem()->id; + if (itemId >= Item::record_13_Id && itemId <= Item::record_wait_Id) + { + // And if the jukebox already has a disk inside + auto tileEntity = dynamic_pointer_cast(level->getTileEntity(x, y, z)); + if (tileEntity != nullptr && tileEntity->getRecord() == nullptr) + { + return IDS_TOOLTIPS_PLAY; + } + } + } + + // If the player doesn't, we can display the eject tooltip + if (Tile::jukebox->TestUse(level, x, y, z, player)) + { + return IDS_TOOLTIPS_EJECT; + } + + return 0; +} diff --git a/Minecraft.World/JukeboxTile.h b/Minecraft.World/JukeboxTile.h index 0e41bf22..ba892395 100644 --- a/Minecraft.World/JukeboxTile.h +++ b/Minecraft.World/JukeboxTile.h @@ -57,4 +57,6 @@ public: virtual void registerIcons(IconRegister *iconRegister); virtual bool hasAnalogOutputSignal(); virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; }; diff --git a/Minecraft.World/LeashFenceKnotEntity.cpp b/Minecraft.World/LeashFenceKnotEntity.cpp index 5aa0408f..b27c065c 100644 --- a/Minecraft.World/LeashFenceKnotEntity.cpp +++ b/Minecraft.World/LeashFenceKnotEntity.cpp @@ -167,4 +167,24 @@ shared_ptr LeashFenceKnotEntity::findKnotAt(Level *level, delete knots; } return nullptr; -} \ No newline at end of file +} + +int LeashFenceKnotEntity::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_UNLEASH; +} + +int LeashFenceKnotEntity::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + if (heldItem != nullptr && heldItem->getItem() != nullptr && heldItem->getItem()->id == Item::lead_Id) + { + if (LeashItem::bindPlayerMobsTest(player, level, player->x, player->y, player->z)) + { + return IDS_TOOLTIPS_ATTACH; + } + } + + return IDS_TOOLTIPS_UNLEASH; +} diff --git a/Minecraft.World/LeashFenceKnotEntity.h b/Minecraft.World/LeashFenceKnotEntity.h index 3838cb78..f201041d 100644 --- a/Minecraft.World/LeashFenceKnotEntity.h +++ b/Minecraft.World/LeashFenceKnotEntity.h @@ -4,7 +4,7 @@ class LeashFenceKnotEntity : public HangingEntity { - + public: eINSTANCEOF GetType() { return eTYPE_LEASHFENCEKNOT; }; static Entity *create(Level *level) { return new LeashFenceKnotEntity(level); } @@ -34,4 +34,8 @@ public: virtual bool survives(); static shared_ptr createAndAddKnot(Level *level, int x, int y, int z); static shared_ptr findKnotAt(Level *level, int x, int y, int z); -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/LeashItem.cpp b/Minecraft.World/LeashItem.cpp index 036b6f2b..10a8c726 100644 --- a/Minecraft.World/LeashItem.cpp +++ b/Minecraft.World/LeashItem.cpp @@ -68,7 +68,7 @@ bool LeashItem::bindPlayerMobsTest(shared_ptr player, Level *level, int { // look for entities that can be attached to the fence double range = 7; - vector > *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); + vector> *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); if (mobs != nullptr) { @@ -79,4 +79,26 @@ bool LeashItem::bindPlayerMobsTest(shared_ptr player, Level *level, int } } return false; -} \ No newline at end of file +} + +int LeashItem::getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + int targetTile = level->getTile(x, y, z); + // Not4J Anaël: We need to check if the target block is a fence because leashes can only attach to those + if (targetTile > 0 && Tile::tiles[targetTile] != nullptr) + { + if (targetTile == Tile::fence_Id) + { + return IDS_TOOLTIPS_ATTACH; + } + } + } + + return 0; +} diff --git a/Minecraft.World/LeashItem.h b/Minecraft.World/LeashItem.h index 373bfdfa..a10c90bd 100644 --- a/Minecraft.World/LeashItem.h +++ b/Minecraft.World/LeashItem.h @@ -10,4 +10,10 @@ public: bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); static bool bindPlayerMobs(shared_ptr player, Level *level, int x, int y, int z); static bool bindPlayerMobsTest(shared_ptr player, Level *level, int x, int y, int z); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const override; }; \ No newline at end of file diff --git a/Minecraft.World/LeverTile.cpp b/Minecraft.World/LeverTile.cpp index 3c4af525..ae366631 100644 --- a/Minecraft.World/LeverTile.cpp +++ b/Minecraft.World/LeverTile.cpp @@ -358,3 +358,8 @@ bool LeverTile::isSignalSource() { return true; } + +int LeverTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/LeverTile.h b/Minecraft.World/LeverTile.h index 2f054e57..e0b9d8e4 100644 --- a/Minecraft.World/LeverTile.h +++ b/Minecraft.World/LeverTile.h @@ -33,4 +33,5 @@ public: virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); virtual bool isSignalSource(); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; }; diff --git a/Minecraft.World/MilkBucketItem.cpp b/Minecraft.World/MilkBucketItem.cpp index ee358f38..d89ac0ad 100644 --- a/Minecraft.World/MilkBucketItem.cpp +++ b/Minecraft.World/MilkBucketItem.cpp @@ -38,4 +38,9 @@ shared_ptr MilkBucketItem::use(shared_ptr instance, { player->startUsingItem(instance, getUseDuration(instance)); return instance; -} \ No newline at end of file +} + +int MilkBucketItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_DRINK; +} diff --git a/Minecraft.World/MilkBucketItem.h b/Minecraft.World/MilkBucketItem.h index f2cff3ea..6ceab59e 100644 --- a/Minecraft.World/MilkBucketItem.h +++ b/Minecraft.World/MilkBucketItem.h @@ -14,4 +14,5 @@ public: virtual int getUseDuration(shared_ptr itemInstance); virtual UseAnim getUseAnimation(shared_ptr itemInstance); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); -}; \ No newline at end of file + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/Minecart.cpp b/Minecraft.World/Minecart.cpp index 9d50f33f..d32d2a92 100644 --- a/Minecraft.World/Minecart.cpp +++ b/Minecraft.World/Minecart.cpp @@ -1081,4 +1081,16 @@ bool Minecart::hasCustomName() wstring Minecart::getCustomName() { return name; -} \ No newline at end of file +} + +int Minecart::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int Minecart::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return IDS_TOOLTIPS_RIDE; +} diff --git a/Minecraft.World/Minecart.h b/Minecraft.World/Minecart.h index e4a9121c..656523ab 100644 --- a/Minecraft.World/Minecart.h +++ b/Minecraft.World/Minecart.h @@ -121,4 +121,9 @@ public: virtual wstring getAName(); virtual bool hasCustomName(); virtual wstring getCustomName(); + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/MinecartChest.cpp b/Minecraft.World/MinecartChest.cpp index af137826..e620a749 100644 --- a/Minecraft.World/MinecartChest.cpp +++ b/Minecraft.World/MinecartChest.cpp @@ -48,4 +48,16 @@ Tile *MinecartChest::getDefaultDisplayTile() int MinecartChest::getDefaultDisplayOffset() { return 8; -} \ No newline at end of file +} + +int MinecartChest::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int MinecartChest::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return IDS_TOOLTIPS_OPEN; +} diff --git a/Minecraft.World/MinecartChest.h b/Minecraft.World/MinecartChest.h index 5eccb7e6..143877f2 100644 --- a/Minecraft.World/MinecartChest.h +++ b/Minecraft.World/MinecartChest.h @@ -20,4 +20,8 @@ public: virtual int getType(); virtual Tile *getDefaultDisplayTile(); virtual int getDefaultDisplayOffset(); -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/MinecartFurnace.cpp b/Minecraft.World/MinecartFurnace.cpp index 5843c935..7c4bcaac 100644 --- a/Minecraft.World/MinecartFurnace.cpp +++ b/Minecraft.World/MinecartFurnace.cpp @@ -1,3 +1,4 @@ +#include "Minecart.h" #include "stdafx.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.entity.h" @@ -26,7 +27,7 @@ MinecartFurnace::MinecartFurnace(Level *level, double x, double y, double z) : M // 4J Added int MinecartFurnace::getContainerType() { - return ContainerOpenPacket::MINECART_HOPPER; + return ContainerOpenPacket::MINECART_HOPPER; } int MinecartFurnace::getType() @@ -106,10 +107,10 @@ void MinecartFurnace::applyNaturalSlowdown() sd = Mth::sqrt(sd); xPush /= sd; zPush /= sd; - + //from 0.05 to 0.1 - double speed = 0.1; - + double speed = 0.1; + xd *= 0.8f; yd *= 0; zd *= 0.8f; @@ -182,4 +183,27 @@ Tile *MinecartFurnace::getDefaultDisplayTile() int MinecartFurnace::getDefaultDisplayData() { return 2; -} \ No newline at end of file +} + +int MinecartFurnace::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int MinecartFurnace::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (heldItemId == Item::coal_Id) + { + return IDS_TOOLTIPS_USE; + } + + return 0; +} diff --git a/Minecraft.World/MinecartFurnace.h b/Minecraft.World/MinecartFurnace.h index aa8bf9e0..d71885f8 100644 --- a/Minecraft.World/MinecartFurnace.h +++ b/Minecraft.World/MinecartFurnace.h @@ -48,4 +48,8 @@ protected: public: Tile *getDefaultDisplayTile(); int getDefaultDisplayData(); -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/MinecartHopper.cpp b/Minecraft.World/MinecartHopper.cpp index 8bf02f8f..67476768 100644 --- a/Minecraft.World/MinecartHopper.cpp +++ b/Minecraft.World/MinecartHopper.cpp @@ -162,4 +162,16 @@ void MinecartHopper::setCooldown(int time) bool MinecartHopper::isOnCooldown() { return cooldownTime > 0; -} \ No newline at end of file +} + +int MinecartHopper::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int MinecartHopper::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return IDS_TOOLTIPS_OPEN; +} diff --git a/Minecraft.World/MinecartHopper.h b/Minecraft.World/MinecartHopper.h index 54c97b38..9f55ba2e 100644 --- a/Minecraft.World/MinecartHopper.h +++ b/Minecraft.World/MinecartHopper.h @@ -61,4 +61,8 @@ public: virtual void startOpen() { MinecartContainer::startOpen(); } virtual void stopOpen() { MinecartContainer::stopOpen(); } virtual bool canPlaceItem(int slot, shared_ptr item) { return MinecartContainer::canPlaceItem(slot, item); } -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/MinecartSpawner.cpp b/Minecraft.World/MinecartSpawner.cpp index 8dd54d01..ee3223a5 100644 --- a/Minecraft.World/MinecartSpawner.cpp +++ b/Minecraft.World/MinecartSpawner.cpp @@ -92,4 +92,16 @@ void MinecartSpawner::tick() BaseMobSpawner *MinecartSpawner::getSpawner() { return spawner; -} \ No newline at end of file +} + +int MinecartSpawner::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int MinecartSpawner::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return 0; +} diff --git a/Minecraft.World/MinecartSpawner.h b/Minecraft.World/MinecartSpawner.h index a0b7944f..42cdac52 100644 --- a/Minecraft.World/MinecartSpawner.h +++ b/Minecraft.World/MinecartSpawner.h @@ -42,4 +42,8 @@ public: virtual void handleEntityEvent(byte eventId); virtual void tick(); virtual BaseMobSpawner *getSpawner(); -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/MinecartTNT.cpp b/Minecraft.World/MinecartTNT.cpp index 18681aa4..4d22aae5 100644 --- a/Minecraft.World/MinecartTNT.cpp +++ b/Minecraft.World/MinecartTNT.cpp @@ -177,4 +177,16 @@ void MinecartTNT::addAdditonalSaveData(CompoundTag *tag) { Minecart::addAdditonalSaveData(tag); tag->putInt(L"TNTFuse", fuse); -} \ No newline at end of file +} + +int MinecartTNT::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_MINE; +} + +int MinecartTNT::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return 0; +} diff --git a/Minecraft.World/MinecartTNT.h b/Minecraft.World/MinecartTNT.h index 8637803c..72e7fc22 100644 --- a/Minecraft.World/MinecartTNT.h +++ b/Minecraft.World/MinecartTNT.h @@ -36,8 +36,12 @@ public: virtual bool isPrimed(); virtual float getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile); virtual bool shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); protected: virtual void readAdditionalSaveData(CompoundTag *tag); virtual void addAdditonalSaveData(CompoundTag *tag); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Mob.cpp b/Minecraft.World/Mob.cpp index 4f1fe6ca..1cea73e4 100644 --- a/Minecraft.World/Mob.cpp +++ b/Minecraft.World/Mob.cpp @@ -286,7 +286,7 @@ void Mob::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) playerBonusLevel, [this](int maxExclusive) -> int { return random->nextInt(maxExclusive); }, isOnFire()); - + if (!drops.empty()) { @@ -1120,4 +1120,32 @@ void Mob::setLevel(Level *level) navigation->setLevel(level); goalSelector.setLevel(level); targetSelector.setLevel(level); -} \ No newline at end of file +} + +int Mob::getInteractTooltipId(Level* level, std::shared_ptr player, std::shared_ptr heldItem) +{ + // Not4J Anaël: Unleash if leashed + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + int heldItemId = heldItem->getItem()->id; + + // Leash mobs + if (heldItemId == Item::lead_Id && !this->isLeashed() && this->canBeLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + + // Give a name (nametag) + if (heldItemId == Item::name_tag_Id) + { + return IDS_TOOLTIPS_NAME; + } + } + + return 0; +} diff --git a/Minecraft.World/Mob.h b/Minecraft.World/Mob.h index 62a9661d..d043623c 100644 --- a/Minecraft.World/Mob.h +++ b/Minecraft.World/Mob.h @@ -176,7 +176,7 @@ public: /** * Added this method so mobs can handle their own spawn settings instead of * hacking MobSpawner.java - * + * * @param groupData * TODO * @return TODO @@ -227,4 +227,7 @@ public: // 4J Added override to update ai elements when loading entity from schematics virtual void setLevel(Level *level); + virtual int getInteractTooltipId(Level* level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/Mushroom.cpp b/Minecraft.World/Mushroom.cpp index 72bcfd01..0467f58f 100644 --- a/Minecraft.World/Mushroom.cpp +++ b/Minecraft.World/Mushroom.cpp @@ -112,4 +112,4 @@ bool Mushroom::growTree(Level *level, int x, int y, int z, Random *random, bool if( f != nullptr ) delete f; return true; -} \ No newline at end of file +} diff --git a/Minecraft.World/MushroomCow.cpp b/Minecraft.World/MushroomCow.cpp index 45653285..f151eaa3 100644 --- a/Minecraft.World/MushroomCow.cpp +++ b/Minecraft.World/MushroomCow.cpp @@ -26,18 +26,18 @@ bool MushroomCow::mobInteract(shared_ptr player) shared_ptr item = player->inventory->getSelected(); if (item != nullptr && item->id == Item::bowl_Id && getAge() >= 0) { - if (item->count == 1) + if (item->count == 1) { player->inventory->setItem(player->inventory->selected, std::make_shared(Item::mushroom_stew)); return true; } - if (player->inventory->add(std::make_shared(Item::mushroom_stew)) && !player->abilities.instabuild) + if (player->inventory->add(std::make_shared(Item::mushroom_stew)) && !player->abilities.instabuild) { player->inventory->removeItem(player->inventory->selected, 1); return true; } - } + } // 4J: Do not allow shearing if we can't create more cows if (item != nullptr && item->id == Item::shears_Id && getAge() >= 0 && level->canCreateMore(eTYPE_COW, Level::eSpawnType_Breed)) { @@ -83,3 +83,56 @@ shared_ptr MushroomCow::getBreedOffspring(shared_ptr targe return nullptr; } } + +int MushroomCow::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } +} + +int MushroomCow::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + heldItemId = heldItem->getItem()->id; + + if (this->isLeashed() && this->getLeashHolder() == player) + return IDS_TOOLTIPS_UNLEASH; + + // It's an item + switch (heldItemId) + { + // Things to USE + case Item::name_tag_Id: + return IDS_TOOLTIPS_NAME; + + case Item::lead_Id: + if (!this->isLeashed()) + return IDS_TOOLTIPS_LEASH; + + case Item::bowl_Id: + case Item::bucket_Id: // You can milk a mooshroom with either a bowl (mushroom soup) or a bucket (milk)! + return IDS_TOOLTIPS_MILK; + + case Item::shears_Id: + if (!this->isBaby()) + { + return IDS_TOOLTIPS_SHEAR; + } + + default: + if (!this->isBaby() && !this->isInLove() && (this->getAge() == 0) && this->isFood(heldItem)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + + case -1: + break; // 4J-JEV: Empty hand. + } + + return 0; +} diff --git a/Minecraft.World/MushroomCow.h b/Minecraft.World/MushroomCow.h index fb87bc67..3cdf0f82 100644 --- a/Minecraft.World/MushroomCow.h +++ b/Minecraft.World/MushroomCow.h @@ -14,4 +14,8 @@ public: virtual bool mobInteract(shared_ptr player); virtual bool canSpawn(); // 4J added virtual shared_ptr getBreedOffspring(shared_ptr target); -}; \ No newline at end of file + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/NoteBlockTile.cpp b/Minecraft.World/NoteBlockTile.cpp index 12b2921a..8588afc5 100644 --- a/Minecraft.World/NoteBlockTile.cpp +++ b/Minecraft.World/NoteBlockTile.cpp @@ -84,3 +84,17 @@ bool NoteBlockTile::triggerEvent(Level *level, int x, int y, int z, int i, int n return true; } + +int NoteBlockTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_CHANGEPITCH; +} + +int NoteBlockTile::getAttackTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + if (player != nullptr && !player->abilities.instabuild) + { + return IDS_TOOLTIPS_PLAY; + } + return IDS_TOOLTIPS_MINE; +} diff --git a/Minecraft.World/NoteBlockTile.h b/Minecraft.World/NoteBlockTile.h index e072b5e6..9daf1fa2 100644 --- a/Minecraft.World/NoteBlockTile.h +++ b/Minecraft.World/NoteBlockTile.h @@ -3,7 +3,7 @@ class Player; -class NoteBlockTile : public BaseEntityTile + class NoteBlockTile : public BaseEntityTile { public: NoteBlockTile(int id); @@ -13,4 +13,7 @@ public: virtual void attack(Level *level, int x, int y, int z, shared_ptr player); virtual shared_ptr newTileEntity(Level *level); virtual bool triggerEvent(Level *level, int x, int y, int z, int i, int note); -}; \ No newline at end of file + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; + virtual int getAttackTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; +}; diff --git a/Minecraft.World/Ocelot.cpp b/Minecraft.World/Ocelot.cpp index 0ee2e63a..9eaef619 100644 --- a/Minecraft.World/Ocelot.cpp +++ b/Minecraft.World/Ocelot.cpp @@ -307,7 +307,7 @@ void Ocelot::setCatType(int type) bool Ocelot::canSpawn() { - + //return level->random->nextInt(3) != 0; when checkSpawnObstruction is implemented // artificially make ozelots more rare if (level->random->nextInt(3) == 0) @@ -383,4 +383,80 @@ bool Ocelot::isSittingOnTile() { byte current = entityData->getByte(DATA_FLAGS_ID); return (current & 0x02) > 0; -} \ No newline at end of file +} + +int Ocelot::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int Ocelot::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + else if (heldItemId == Item::lead_Id) + { + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + } + else if (heldItemId == Item::name_tag_Id) + { + return IDS_TOOLTIPS_NAME; + } + else if (this->isTame()) + { + // 4J-PB - if you have a raw fish in your hand, you will feed the this rather than have it sit/follow + if (this->isFood(heldItem)) + { + if (!this->isBaby()) + { + if (!this->isInLove()) + { + if (this->getAge() == 0) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + else + { + return IDS_TOOLTIPS_FEED; + } + } + } + else if (equalsIgnoreCase(player->getUUID(), this->getOwnerUUID()) && !this->isSittingOnTile()) + { + if (this->isSitting()) + { + return IDS_TOOLTIPS_FOLLOWME; + } + else + { + return IDS_TOOLTIPS_SIT; + } + } + } + else if (heldItemId >= 0) + { + if (this->isFood(heldItem)) + { + return IDS_TOOLTIPS_TAME; + } + } +} diff --git a/Minecraft.World/Ocelot.h b/Minecraft.World/Ocelot.h index cdc7123b..a7abbf67 100644 --- a/Minecraft.World/Ocelot.h +++ b/Minecraft.World/Ocelot.h @@ -92,4 +92,9 @@ private: void setSittingOnTile(bool val); public: bool isSittingOnTile(); -}; \ No newline at end of file + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/Pig.cpp b/Minecraft.World/Pig.cpp index 046c847d..cf8fab04 100644 --- a/Minecraft.World/Pig.cpp +++ b/Minecraft.World/Pig.cpp @@ -74,35 +74,35 @@ bool Pig::canBeControlledByRider() return item != nullptr && item->id == Item::carrot_on_a_stick_Id; } -void Pig::defineSynchedData() +void Pig::defineSynchedData() { Animal::defineSynchedData(); entityData->define(DATA_SADDLE_ID, static_cast(0)); } -void Pig::addAdditonalSaveData(CompoundTag *tag) +void Pig::addAdditonalSaveData(CompoundTag *tag) { Animal::addAdditonalSaveData(tag); tag->putBoolean(L"Saddle", hasSaddle()); } -void Pig::readAdditionalSaveData(CompoundTag *tag) +void Pig::readAdditionalSaveData(CompoundTag *tag) { Animal::readAdditionalSaveData(tag); setSaddle(tag->getBoolean(L"Saddle")); } -int Pig::getAmbientSound() +int Pig::getAmbientSound() { return eSoundType_MOB_PIG_AMBIENT; } -int Pig::getHurtSound() +int Pig::getHurtSound() { return eSoundType_MOB_PIG_AMBIENT; } -int Pig::getDeathSound() +int Pig::getDeathSound() { return eSoundType_MOB_PIG_DEATH; } @@ -116,7 +116,7 @@ bool Pig::mobInteract(shared_ptr player) { if(!Animal::mobInteract(player)) { - if (hasSaddle() && !level->isClientSide && (rider.lock() == nullptr || rider.lock() == player)) + if (hasSaddle() && !level->isClientSide && (rider.lock() == nullptr || rider.lock() == player)) { // 4J HEG - Fixed issue with player not being able to dismount pig (issue #4479) player->ride( rider.lock() == player ? nullptr : shared_from_this() ); @@ -127,7 +127,7 @@ bool Pig::mobInteract(shared_ptr player) return true; } -int Pig::getDeathLoot() +int Pig::getDeathLoot() { if (this->isOnFire() ) return Item::cooked_porkchop->id; return Item::porkchop_Id; @@ -153,18 +153,18 @@ void Pig::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } */ -bool Pig::hasSaddle() +bool Pig::hasSaddle() { return (entityData->getByte(DATA_SADDLE_ID) & 1) != 0; } -void Pig::setSaddle(bool value) +void Pig::setSaddle(bool value) { - if (value) + if (value) { entityData->set(DATA_SADDLE_ID, static_cast(1)); - } - else + } + else { entityData->set(DATA_SADDLE_ID, static_cast(0)); } @@ -179,7 +179,7 @@ void Pig::thunderHit(const LightningBolt *lightningBolt) remove(); } -void Pig::causeFallDamage(float distance) +void Pig::causeFallDamage(float distance) { Animal::causeFallDamage(distance); if ( (distance > 5) && rider.lock() != nullptr && rider.lock()->instanceof(eTYPE_PLAYER) ) @@ -213,3 +213,66 @@ ControlledByPlayerGoal *Pig::getControlGoal() { return controlGoal; } + +int Pig::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int Pig::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + else if (heldItemId == Item::lead_Id) + { + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + } + else if (heldItemId == Item::name_tag_Id) + { + return IDS_TOOLTIPS_NAME; + } + else if (this->hasSaddle()) // does the pig have a saddle? + { + return IDS_TOOLTIPS_MOUNT; + } + else if (!this->isBaby()) + { + if (player->inventory->IsHeldItem()) + { + switch (heldItemId) + { + case Item::saddle_Id: + return IDS_TOOLTIPS_SADDLE; + + default: + { + if (!this->isInLove() && (this->getAge() == 0) && this->isFood(heldItem)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + break; + } + } + } + + return 0; +} diff --git a/Minecraft.World/Pig.h b/Minecraft.World/Pig.h index 63d1a0af..1fa47d13 100644 --- a/Minecraft.World/Pig.h +++ b/Minecraft.World/Pig.h @@ -62,4 +62,8 @@ public: virtual shared_ptr getBreedOffspring(shared_ptr target); bool isFood(shared_ptr itemInstance); ControlledByPlayerGoal *getControlGoal(); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); }; diff --git a/Minecraft.World/Player.cpp b/Minecraft.World/Player.cpp index 515ced02..07c28f2c 100644 --- a/Minecraft.World/Player.cpp +++ b/Minecraft.World/Player.cpp @@ -1202,7 +1202,7 @@ void Player::awardKillScore(shared_ptr victim, int awardPoints) if ( objective ) { Score *score = getScoreboard()->getPlayerScore(getAName(), objective); - if ( score ) + if ( score ) score->increment(); } } @@ -1450,7 +1450,7 @@ void Player::setDefaultHeadHeight() bool Player::hurt(DamageSource *source, float dmg) { if (isInvulnerable()) return false; - + if ( hasInvulnerablePrivilege() || (abilities.invulnerable && !source->isBypassInvul()) ) return false; @@ -3029,39 +3029,39 @@ unsigned int Player::getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlay _SkinAdjustments Player::getSkinAdjustmentsById(unsigned int skinId) { - + _SkinAdjustments adj = _SkinAdjustments(); - + if ((int)skinId < 0) { - + app.GetSkinAdjustments(&adj, skinId); - + unsigned int rawId = skinId & 0x7FFFFFFF; - - if (rawId == 2 || rawId == 3 || rawId == 0xC8 || rawId == 0xC9 || - rawId == 0x194 || rawId == 0x195 || rawId == 0x1F8 || rawId == 0x220 || + + if (rawId == 2 || rawId == 3 || rawId == 0xC8 || rawId == 0xC9 || + rawId == 0x194 || rawId == 0x195 || rawId == 0x1F8 || rawId == 0x220 || rawId == 0x23A || rawId == 0x23D || rawId == 0x247) { - - adj.data[17] = 2; + + adj.data[17] = 2; } else if (rawId == 0x1F4) { - + adj.data[17] = 5; } else if (rawId == 0x1FA) { - + adj.data[17] = 6; } } - + return adj; } @@ -3539,4 +3539,24 @@ void Player::SetPlayerNameValidState(bool bState) bool Player::isSpectator() { return false; -} \ No newline at end of file +} + +int Player::getAttackTooltipId(std::shared_ptr player) +{ + if (!this->hasInvisiblePrivilege()) // This means they are invisible, not just that they have the privilege + { + if (app.GetGameHostOption(eGameHostOption_PvP) && player->isAllowedToAttackPlayers()) + { + return IDS_TOOLTIPS_HIT; + } + } + + return 0; +} + +int Player::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + return 0; +} diff --git a/Minecraft.World/Player.cpp.orig b/Minecraft.World/Player.cpp.orig new file mode 100644 index 00000000..515ced02 --- /dev/null +++ b/Minecraft.World/Player.cpp.orig @@ -0,0 +1,3542 @@ +// 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.ai.attributes.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.boss.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.scores.h" +#include "net.minecraft.world.scores.criteria.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" +#include "ElytraItem.h" + + + +void Player::_init() +{ + registerAttributes(); + setHealth(getMaxHealth()); + + inventory = std::make_shared(this); + + userType = 0; + oBob = bob = 0.0f; + + xCloakO = yCloakO = zCloakO = 0.0; + xCloak = yCloak = zCloak = 0.0; + + m_isSleeping = false; + + customTextureUrl = L""; + customTextureUrl2 = L""; + m_uiPlayerCurrentSkin=0; + + bedPosition = nullptr; + + sleepCounter = 0; + deathFadeCounter=0; + + bedOffsetX = bedOffsetY = bedOffsetZ = 0.0f; + stats = nullptr; + + respawnPosition = nullptr; + respawnForced = false; + minecartAchievementPos = nullptr; + + fishing = nullptr; + + distanceWalk = distanceSwim = distanceFall = distanceClimb = distanceMinecart = distanceBoat = distancePig = 0; + + m_uiDebugOptions=0L; + + jumpTriggerTime = 0; + ticksElytraFlying = 0; + rotateElytraX = 0.2617994f; + rotateElytraY = 0.0f; + rotateElytraZ = -0.2617994f; + m_elytraImpactYd = 0.0f; + m_wasElytraFlying = false; + m_elytraFallProtectTicks = 0; + m_elytraMaxY = 0.0f; + m_fireworkBoostTicks = 0; + m_elytraRocketCooldown = 0; + + takeXpDelay = 0; + experienceLevel = totalExperience = 0; + experienceProgress = 0.0f; + + useItem = nullptr; + useItemDuration = 0; + + defaultWalkSpeed = 0.1f; + defaultFlySpeed = 0.02f; + + lastLevelUpTime = 0; + + m_uiGamePrivileges = 0; + + m_ppAdditionalModelParts=nullptr; + m_bCheckedForModelParts=false; + m_bCheckedDLCForModelParts=false; + + m_ppSkinOffsets=nullptr; + m_bCheckedForSkinOffsets=false; + m_bCheckedDLCForSkinOffsets=false; + +#if defined(__PS3__) || defined(__ORBIS__) + m_ePlayerNameValidState=ePlayerNameValid_NotSet; +#endif + + enderChestInventory = std::make_shared(); + + m_bAwardedOnARail=false; +} + +Player::Player(Level *level, const wstring &name) : LivingEntity( 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(); + + this->name = name; + + _init(); + MemSect(11); + inventoryMenu = new InventoryMenu(inventory, !level->isClientSide, this); + MemSect(0); + + containerMenu = inventoryMenu; + + heightOffset = 1.62f; + Pos *spawnPos = level->getSharedSpawnPos(); + moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); + delete spawnPos; + lastChangedBlockPos = BlockPos(x, y, z); + + rotOffs = 180; + flameTime = 20; + + 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; + +#ifndef _XBOX_ONE + // 4J: Set UUID to name on none-XB1 consoles, may change in future but for now + // ownership of animals on these consoles is done by name + setUUID(name); +#endif +} + +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; +} + +void Player::registerAttributes() +{ + LivingEntity::registerAttributes(); + + getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(1); +} + +void Player::defineSynchedData() +{ + LivingEntity::defineSynchedData(); + + entityData->define(DATA_PLAYER_FLAGS_ID, static_cast(0)); + entityData->define(DATA_PLAYER_ABSORPTION_ID, static_cast(0)); + entityData->define(DATA_SCORE_ID, (int) 0); +} + +shared_ptr Player::getUseItem() +{ + return useItem; +} + +int Player::getUseItemDuration() +{ + return useItemDuration; +} + +bool Player::isUsingItem() +{ + return useItem != nullptr; +} + +int Player::getTicksUsingItem() +{ + if (isUsingItem()) + { + return useItem->getUseDuration() - useItemDuration; + } + return 0; +} + +void Player::releaseUsingItem() +{ + if (useItem != nullptr) + { + 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; +} + +// 4J Stu - Added for things that should only be ticked once per simulation frame +void Player::updateFrameTick() +{ + if (useItem != nullptr) + { + 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 nullptr check as well for the other possible not equals (useItem is not nullptr 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 == nullptr || !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; + } + } +} + +void Player::tick() +{ + if(level->isClientSide) + { + // 4J Stu - Server player calls this differently so that it only happens once per simulation tick + updateFrameTick(); + } + + LivingEntity::tick(); + + BlockPos currentBlockPos(Mth::floor(x), Mth::floor(y), Mth::floor(z)); + if (currentBlockPos != lastChangedBlockPos) + { + lastChangedBlockPos = currentBlockPos; + onChangedBlock(currentBlockPos); + } + + if (!level->isClientSide) + { + if (containerMenu != nullptr && !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 == nullptr) + { + if( minecartAchievementPos != nullptr ) + { + delete minecartAchievementPos; + minecartAchievementPos = nullptr; + } + } + + 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 _WINDOWS64 + // 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::diamond_pickaxe, 1 )) ); +#endif + +#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::diamond_pickaxe, 1 )) ); + // #endif +#endif + +#ifdef _DURANGO + // 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::diamond_pickaxe, 1 )) ); +#endif +#endif + // 4J-PB - Throw items out at the start of the level + //this->drop( new ItemInstance( Item::diamond_pickaxe, 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.diamond_pickaxe); + // 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 ) ) ); + + int poweredCount = 0; + for(int i = 10; i < 2800; ++i) + { + level->setTileAndData(x+i,y-1,z-2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y,z-2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+1,z-2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z-2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z-2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + + level->setTileAndData(x+i,y-1,z-1,Tile::stonebrick_Id,0,Tile::UPDATE_CLIENTS); + if(i%20 == 0) + { + level->setTileAndData(x+i,y,z-1,Tile::redstone_torch_Id,0,Tile::UPDATE_CLIENTS); + poweredCount = 4; + } + else + { + level->setTileAndData(x+i,y,z-1,0,0,Tile::UPDATE_CLIENTS); + } + level->setTileAndData(x+i,y+1,z-1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z-1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z-1,0,0,Tile::UPDATE_CLIENTS); + + level->setTileAndData(x+i,y-1,z,Tile::stonebrick_Id,0,Tile::UPDATE_CLIENTS); + if(poweredCount>0) + { + level->setTileAndData(x+i,y,z,Tile::golden_rail_Id,0,Tile::UPDATE_CLIENTS); + --poweredCount; + } + else + { + level->setTileAndData(x+i,y,z,Tile::rail_Id,0,Tile::UPDATE_CLIENTS); + } + level->setTileAndData(x+i,y+1,z,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z,0,0,Tile::UPDATE_CLIENTS); + + level->setTileAndData(x+i,y-1,z+1,Tile::stonebrick_Id,0,Tile::UPDATE_CLIENTS); + if((i+5)%20 == 0) + { + level->setTileAndData(x+i,y,z+1,Tile::torch_Id,0,Tile::UPDATE_CLIENTS); + } + else + { + level->setTileAndData(x+i,y,z+1,0,0,Tile::UPDATE_CLIENTS); + } + level->setTileAndData(x+i,y+1,z+1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z+1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z+1,0,0,Tile::UPDATE_CLIENTS); + + level->setTileAndData(x+i,y-1,z+2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y,z+2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+1,z+2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z+2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z+2,Tile::quartz_block_Id,0,Tile::UPDATE_CLIENTS); + } + madeTrack = true; + } +#endif + } + //End 4J sTU +} + +int Player::getPortalWaitTime() +{ + return abilities.invulnerable ? 0 : SharedConstants::TICKS_PER_SECOND * 4; +} + +int Player::getDimensionChangingDelay() +{ + return SharedConstants::TICKS_PER_SECOND / 2; +} + +void Player::playSound(int iSound, float volume, float pitch) +{ + // this sound method will play locally for the local player, and + // broadcast to remote players + level->playPlayerSound(dynamic_pointer_cast(shared_from_this()), iSound, volume, pitch); +} + +void Player::spawnEatParticles(shared_ptr useItem, int count) +{ + if (useItem->getUseAnimation() == UseAnim_drink) + { + playSound(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 + playSound(eSoundType_RANDOM_EAT, 0.5f + 0.5f * random->nextInt(2), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + } +} + +void Player::completeUsingItem() +{ + if (useItem != nullptr) + { + spawnEatParticles(useItem, 16); + + int oldCount = useItem->count; + shared_ptr itemInstance = useItem->useTimeDepleted(level, dynamic_pointer_cast(shared_from_this())); + if (itemInstance != useItem || (itemInstance != nullptr && 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 + { + LivingEntity::handleEntityEvent(id); + } +} + +bool Player::isImmobile() +{ + return getHealth() <= 0 || isSleeping(); +} + +void Player::onChangedBlock(BlockPos pos) +{ + if (true /*!isSpectator()*/) // spectator is not a thing yet + { + LivingEntity::onChangedBlock(pos); + } +} + +void Player::closeContainer() +{ + containerMenu = inventoryMenu; +} + +void Player::ride(shared_ptr e) +{ + if (riding != nullptr && e == nullptr) + { + if (!level->isClientSide) findStandUpPosition(riding); + + if (riding != nullptr) + { + riding->rider = weak_ptr(); + } + riding = nullptr; + + return; + } + this->abilities.flying = false; + LivingEntity::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 = static_cast(defaultSkinIndex); + } + } + + if( playerSkin == eDefaultSkins_ServerSelected) + { + playerSkin = static_cast(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==nullptr) + { + // 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!=nullptr) + { + 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(nullptr); + } + app.SetAnimOverrideBitmask(pDLCSkinFile->getSkinID(),pDLCSkinFile->getAnimOverrideBitmask()); + } + else + { + this->SetAdditionalModelParts(nullptr); + } + } + 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(nullptr); + + m_bCheckedForSkinOffsets=false; + m_bCheckedDLCForSkinOffsets=false; + this->SetSkinOffsets(nullptr); +} + +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() +{ + if (!level->isClientSide && isSneaking()) + { + ride(nullptr); + setSneaking(false); + return; + } + + double preX = x, preY = y, preZ = z; + float preYRot = yRot, preXRot = xRot; + + LivingEntity::rideTick(); + oBob = bob; + bob = 0; + + checkRidingStatistiscs(x - preX, y - preY, z - preZ); + + // riding can be set to null inside 'Entity::rideTick()'. + if ( riding != nullptr && (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); + LivingEntity::resetPos(); + setHealth(getMaxHealth()); + deathTime = 0; +} + +void Player::serverAiStep() +{ + LivingEntity::serverAiStep(); + updateSwingTime(); +} + + +void Player::aiStep() +{ + if (jumpTriggerTime > 0) jumpTriggerTime--; + if (m_elytraFallProtectTicks > 0) m_elytraFallProtectTicks--; + if (m_elytraRocketCooldown > 0) m_elytraRocketCooldown--; + + + if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth() && level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION)) + { + if (tickCount % 20 * 12 == 0) heal(1); + } + inventory->tick(); + oBob = bob; + + if (jumping && !onGround && yd < 0.0 && fallDistance > 0.0f && !isElytraFlying() && !abilities.flying && jumpTriggerTime == 0) + { + shared_ptr chestItem = inventory->armor[LivingEntity::SLOT_CHEST - 1]; + if (chestItem != nullptr && chestItem->getItem() != nullptr) + { + ElytraItem* elytra = dynamic_cast(chestItem->getItem()); + if (elytra != nullptr && ElytraItem::isFlyEnabled(chestItem)) + setElytraFlying(true); + } + } + + + + LivingEntity::aiStep(); + + if (isElytraFlying() && !onGround) + { + ticksElytraFlying++; + + shared_ptr chestItem = inventory->armor[LivingEntity::SLOT_CHEST - 1]; + if (chestItem == nullptr + || chestItem->count <= 0 + || dynamic_cast(chestItem->getItem()) == nullptr + || !ElytraItem::isFlyEnabled(chestItem)) + setElytraFlying(false); + } + + + + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + if (!level->isClientSide) speed->setBaseValue(abilities.getWalkingSpeed()); + flyingSpeed = defaultFlySpeed; + if (isSprinting()) + { + flyingSpeed += defaultFlySpeed * 0.3f; + } + + setSpeed(static_cast(speed->getValue())); + + float tBob = static_cast(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 = static_cast(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) + { + AABB *pickupArea = nullptr; + if (riding != nullptr && !riding->removed) + { + // if the player is riding, also touch entities under the + // pig/horse + pickupArea = bb->minmax(riding->bb)->grow(1, 0, 1); + } + else + { + pickupArea = bb->grow(1, .5, 1); + } + + vector > *entities = level->getEntities(shared_from_this(), pickupArea); + if (entities != nullptr) + { + for (auto& e : *entities) + { + if ( e && !e->removed) + { + touch(e); + } + } + } + } +} + + +void Player::touch(shared_ptr entity) +{ + entity->playerTouch( dynamic_pointer_cast( shared_from_this() ) ); +} + +int Player::getScore() +{ + return entityData->getInteger(DATA_SCORE_ID); +} + +void Player::setScore(int value) +{ + entityData->set(DATA_SCORE_ID, value); +} + +void Player::increaseScore(int amount) +{ + int score = getScore(); + entityData->set(DATA_SCORE_ID, score + amount); +} + +void Player::die(DamageSource *source) +{ + LivingEntity::die(source); + 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(std::make_shared(Item::apple, 1), true); + } + if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + inventory->dropAll(); + } + + if (source != nullptr) + { + xd = -Mth::cos((hurtDir + yRot) * PI / 180) * 0.1f; + zd = -Mth::sin((hurtDir + yRot) * PI / 180) * 0.1f; + } + else + { + xd = zd = 0; + } + heightOffset = 0.1f; +} + +void Player::awardKillScore(shared_ptr victim, int awardPoints) +{ + increaseScore(awardPoints); + vector *objectives = getScoreboard()->findObjectiveFor(ObjectiveCriteria::KILL_COUNT_ALL); + + //if (victim instanceof Player) + //{ + // awardStat(Stats::playerKills, 1); + // objectives.addAll(getScoreboard().findObjectiveFor(ObjectiveCriteria::KILL_COUNT_PLAYERS)); + //} + //else + //{ + // awardStat(Stats::mobKills, 1); + //} + + if(objectives) + { + for (auto& objective : *objectives) + { + if ( objective ) + { + Score *score = getScoreboard()->getPlayerScore(getAName(), objective); + if ( score ) + score->increment(); + } + } + } +} + +bool Player::isShootable() +{ + return true; +} + +bool Player::isCreativeModeAllowed() +{ + return true; +} + +shared_ptr Player::drop(bool all) +{ + return drop(inventory->removeItem(inventory->selected, all && inventory->getSelected() != nullptr ? inventory->getSelected()->count : 1), false); +} + +shared_ptr Player::drop(shared_ptr item) +{ + return drop(item, false); +} + +shared_ptr Player::drop(shared_ptr item, bool randomly) +{ + if (item == nullptr) return nullptr; + if (item->count == 0) return nullptr; + + shared_ptr thrownItem = std::make_shared(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, bool hasProperTool) +{ + float speed = inventory->getDestroySpeed(tile); + + if (speed > 1) + { + int efficiency = EnchantmentHelper::getDiggingBonus(dynamic_pointer_cast(shared_from_this())); + shared_ptr item = inventory->getSelected(); + + if (efficiency > 0 && item != nullptr) + { + float boost = efficiency * efficiency + 1; + + if (item->canDestroySpecial(tile) || speed > 1) + { + speed += boost; + } + else + { + speed += boost * 0.08f; + } + } + } + + 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(dynamic_pointer_cast(shared_from_this()))) 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) +{ + LivingEntity::readAdditionalSaveData(entityTag); + ListTag *inventoryList = (ListTag *) entityTag->getList(L"Inventory"); + inventory->load(inventoryList); + inventory->selected = entityTag->getInt(L"SelectedItemSlot"); + m_isSleeping = entityTag->getBoolean(L"Sleeping"); + sleepCounter = entityTag->getShort(L"SleepTimer"); + + experienceProgress = entityTag->getFloat(L"XpP"); + enchantmentSeed = entityTag->getInt(L"enchSeed"); + experienceLevel = entityTag->getInt(L"XpLevel"); + totalExperience = entityTag->getInt(L"XpTotal"); + setScore(entityTag->getInt(L"Score")); + + 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")); + respawnForced = entityTag->getBoolean(L"SpawnForced"); + } + + 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) +{ + LivingEntity::addAdditonalSaveData(entityTag); + entityTag->put(L"Inventory", inventory->save(new ListTag())); + entityTag->putInt(L"SelectedItemSlot", inventory->selected); + entityTag->putBoolean(L"Sleeping", m_isSleeping); + entityTag->putShort(L"SleepTimer", static_cast(sleepCounter)); + + entityTag->putFloat(L"XpP", experienceProgress); + entityTag->putInt(L"enchSeed", enchantmentSeed); + entityTag->putInt(L"XpLevel", experienceLevel); + entityTag->putInt(L"XpTotal", totalExperience); + entityTag->putInt(L"Score", getScore()); + + if (respawnPosition != nullptr) + { + entityTag->putInt(L"SpawnX", respawnPosition->x); + entityTag->putInt(L"SpawnY", respawnPosition->y); + entityTag->putInt(L"SpawnZ", respawnPosition->z); + entityTag->putBoolean(L"SpawnForced", respawnForced); + } + + foodData.addAdditonalSaveData(entityTag); + abilities.addSaveData(entityTag); + + entityTag->put(L"EnderItems", enderChestInventory->createTag()); + + // 4J Added + entityTag->putInt(L"GamePrivileges",m_uiGamePrivileges); + +} + +bool Player::openContainer(shared_ptr container) +{ + return true; +} + +bool Player::openHopper(shared_ptr container) +{ + return true; +} + +bool Player::openHopper(shared_ptr container) +{ + return true; +} + +bool Player::openHorseInventory(shared_ptr horse, shared_ptr container) +{ + return true; +} + +bool Player::startEnchanting(int x, int y, int z, const wstring &name) +{ + return true; +} + +bool Player::startRepairing(int x, int y, int z) +{ + return true; +} + +bool Player::startCrafting(int x, int y, int z) +{ + return true; +} + +bool Player::openFireworks(int x, int y, int z) +{ + return true; +} + +float Player::getHeadHeight() +{ + return 0.12f; +} + + +void Player::setDefaultHeadHeight() +{ + heightOffset = 1.62f; +} + +bool Player::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + + 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 ( attacker != nullptr && attacker->instanceof(eTYPE_ARROW) ) + { + shared_ptr arrow = dynamic_pointer_cast(attacker); + if ( arrow->owner != nullptr) + { + attacker = arrow->owner; + } + } + + return LivingEntity::hurt(source, dmg); +} + +bool Player::canHarmPlayer(shared_ptr target) +{ + Team *team = getTeam(); + Team *otherTeam = target->getTeam(); + + if (team == nullptr) + { + return true; + } + if (!team->isAlliedTo(otherTeam)) + { + return true; + } + return team->isAllowFriendlyFire(); +} + +bool Player::canHarmPlayer(wstring targetName) +{ + return true; +} + +void Player::hurtArmor(float 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] != nullptr) { + count++; + } + } + return static_cast(count) / static_cast(inventory->armor.length); +} + +void Player::actuallyHurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return; + if (!source->isBypassArmor() && isBlocking() && dmg > 0) + { + dmg = (1 + dmg) * .5f; + } + dmg = getDamageAfterArmorAbsorb(source, dmg); + dmg = getDamageAfterMagicAbsorb(source, dmg); + + float originalDamage = dmg; + dmg = max(dmg - getAbsorptionAmount(), 0.0f); + setAbsorptionAmount(getAbsorptionAmount() - (originalDamage - dmg)); + if (dmg == 0) return; + + causeFoodExhaustion(source->getFoodExhaustion()); + float oldHealth = getHealth(); + setHealth(getHealth() - dmg); + getCombatTracker()->recordDamage(source, oldHealth, 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 brewing_stand) +{ + return true; +} + +bool Player::openBeacon(shared_ptr beacon) +{ + return true; +} + +bool Player::openTrading(shared_ptr traderTarget, const wstring &name) +{ + return true; +} + +/** +* Opens an iteminstance-dependent user interface. +* +* @param itemInstance +*/ +void Player::openItemInstanceGui(shared_ptr itemInstance, shared_ptr player) +{ + return; +} + +bool Player::interact(shared_ptr entity) +{ + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); + + shared_ptr item = getSelectedItem(); + shared_ptr itemClone = (item != nullptr) ? item->copy() : nullptr; + if ( entity->interact(thisPlayer) ) + { + // [EB]: Added rude check to see if we're still talking about the + // same item; this code caused bucket->milkbucket to be deleted because + // the milkbuckets' stack got decremented to 0. + if (item != nullptr && item == getSelectedItem()) + { + if (item->count <= 0 && !abilities.instabuild) + { + removeSelectedItem(); + } + else if (item->count < itemClone->count && abilities.instabuild) + { + item->count = itemClone->count; + } + } + return true; + } + + if ( (item != nullptr) && entity->instanceof(eTYPE_LIVINGENTITY) ) + { + // 4J - PC Comments + // Hack to prevent item stacks from decrementing if the player has + // the ability to instabuild + if(this->abilities.instabuild) item = itemClone; + if(item->interactEnemy(thisPlayer, 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) && !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::attack(shared_ptr entity) +{ + if (!entity->isAttackable()) + { + return; + } + + if (entity->skipAttackInteraction(shared_from_this())) + { + return; + } + + float dmg = static_cast(getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->getValue()); + + int knockback = 0; + float magicBoost = 0; + + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) + { + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); + shared_ptr mob = dynamic_pointer_cast(entity); + magicBoost = EnchantmentHelper::getDamageBonus(thisPlayer, mob); + knockback += EnchantmentHelper::getKnockbackBonus(thisPlayer, mob); + } + if (isSprinting()) + { + knockback += 1; + } + + if (dmg > 0 || magicBoost > 0) + { + bool bCrit = fallDistance > 0 && !onGround && !onLadder() && !isInWater() && !hasEffect(MobEffect::blindness) && (riding == nullptr) && entity->instanceof(eTYPE_LIVINGENTITY); + if (bCrit && dmg > 0) + { + dmg *= 1.5f; + } + 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 ( entity->instanceof(eTYPE_MOB) && fireAspect > 0 && !entity->isOnFire()) + { + setOnFireTemporatily = true; + entity->setOnFire(1); + } + + DamageSource *damageSource = DamageSource::playerAttack(dynamic_pointer_cast(shared_from_this())); + + if (bCrit) { + damageSource->setIsCritical(); + } + 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); + + + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) + { + shared_ptr mob = dynamic_pointer_cast(entity); + ThornsEnchantment::doThornsAfterAttack(shared_from_this(), mob, random); + } + } + + shared_ptr item = getSelectedItem(); + shared_ptr hurtTarget = entity; + if ( entity->instanceof(eTYPE_MULTIENTITY_MOB_PART) ) + { + shared_ptr multiMob = dynamic_pointer_cast((dynamic_pointer_cast(entity))->parentMob.lock()); + if ( (multiMob != nullptr) && multiMob->instanceof(eTYPE_LIVINGENTITY) ) + { + hurtTarget = dynamic_pointer_cast( multiMob ); + } + } + if ( (item != nullptr) && hurtTarget->instanceof(eTYPE_LIVINGENTITY) ) + { + item->hurtEnemy(dynamic_pointer_cast(hurtTarget), dynamic_pointer_cast( shared_from_this() ) ); + if (item->count <= 0) + { + removeSelectedItem(); + } + } + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) + { + //awardStat(Stats.damageDealt, (int) Math.round(dmg * 10)); + + if (fireAspect > 0 && wasHurt) + { + entity->setOnFire(fireAspect * 4); + } + else if (setOnFireTemporatily) + { + entity->clearFire(); + } + } + + causeFoodExhaustion(FoodConstants::EXHAUSTION_ATTACK); + } + + // if (SharedConstants::INGAME_DEBUG_OUTPUT) + // { + // //sendMessage(ChatMessageComponent.forPlainText("DMG " + dmg + ", " + magicBoost + ", " + knockback)); + // } +} + +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 nullptr; +} + +void Player::remove() +{ + LivingEntity::remove(); + inventoryMenu->removed( dynamic_pointer_cast( shared_from_this() ) ); + if (containerMenu != nullptr) + { + containerMenu->removed( dynamic_pointer_cast( shared_from_this() ) ); + } +} + +bool Player::isInWall() +{ + return !m_isSleeping && LivingEntity::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()) + { + delete monsters; + 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; + } + + if (isRiding()) + { + 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 != nullptr && 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 == nullptr) + { + 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, false); + } +} + + +bool Player::checkBed() +{ + return (level->getTile(bedPosition->x, bedPosition->y, bedPosition->z) == Tile::bed_Id); +} + + +Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos, bool forced) +{ + // 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) + { + Material *bottomMaterial = level->getMaterial(pos->x, pos->y, pos->z); + Material *topMaterial = level->getMaterial(pos->x, pos->y + 1, pos->z); + bool freeFeet = !bottomMaterial->isSolid() && !bottomMaterial->isLiquid(); + bool freeHead = !topMaterial->isSolid() && !topMaterial->isLiquid(); + + if (forced && freeFeet && freeHead) + { + return pos; + } + return nullptr; + } + // 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 != nullptr) + { + 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, static_cast(currentValue | (1 << flag))); + } + else + { + entityData->set(DATA_PLAYER_FLAGS_ID, static_cast(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; +} + +bool Player::isRespawnForced() +{ + return respawnForced; +} + +void Player::setRespawnPosition(Pos *respawnPosition, bool forced) +{ + if (respawnPosition != nullptr) + { + this->respawnPosition = new Pos(*respawnPosition); + respawnForced = forced; + } + else + { + this->respawnPosition = nullptr; + respawnForced = false; + } +} + +void Player::awardStat(Stat *stat, byteArray paramBlob) +{ + if (paramBlob.data != nullptr) + { + delete [] paramBlob.data; + } +} + + +void Player::jumpFromGround() +{ + LivingEntity::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) +{ + if (isSleeping()) + { + return; + } + + double preX = x, preY = y, preZ = z; + + m_elytraImpactYd = (float)yd; + + if (isElytraFlying() && riding == nullptr && !isInWater() && !isInLava()) + { + double preHorizSpeed = Mth::sqrt(xd * xd + zd * zd); + + + if ((float)y > m_elytraMaxY) m_elytraMaxY = (float)y; + + if (yd > -0.5) + fallDistance = 1.0f; + + Vec3* look = getLookAngle(); + float pitchRad = xRot * (PI / 180.0f); + double horizLookLen = Mth::sqrt(look->x * look->x + look->z * look->z); + double horizSpeed = Mth::sqrt(xd * xd + zd * zd); + + + float cosPitch = Mth::cos(pitchRad); + cosPitch = cosPitch * cosPitch; + + + yd += -0.08 + (double)cosPitch * 0.06; + + if (yd < 0.0 && horizLookLen > 0.0) + { + double thrust = yd * -0.1 * (double)cosPitch; + yd += thrust; + xd += look->x * thrust / horizLookLen; + zd += look->z * thrust / horizLookLen; + } + + if (pitchRad < 0.0f && horizLookLen > 0.0) + { + double boost = horizSpeed * (double)(-Mth::sin(pitchRad)) * 0.04; + yd += boost * 3.2; + xd -= look->x * boost / horizLookLen; + zd -= look->z * boost / horizLookLen; + } + + + if (horizLookLen > 0.0) + { + xd += (look->x / horizLookLen * horizSpeed - xd) * 0.1; + zd += (look->z / horizLookLen * horizSpeed - zd) * 0.1; + } + + // Air drag + xd *= 0.99; + yd *= 0.98; + zd *= 0.99; + + if (jumping && abilities.instabuild) + yd += (double)abilities.getFlyingSpeed() * 3.0; + + if (m_fireworkBoostTicks > 0) + { + Vec3 *look = getLookAngle(); + xd += look->x * 0.1 + (look->x * 1.5 - xd) * 0.5; + yd += look->y * 0.1 + (look->y * 1.5 - yd) * 0.5; + zd += look->z * 0.1 + (look->z * 1.5 - zd) * 0.5; + m_fireworkBoostTicks--; + } + + m_elytraImpactYd = (float)yd; + move(xd, yd, zd); + + if (horizontalCollision) + { + double postHorizSpeed = Mth::sqrt(xd * xd + zd * zd); + double speedLost = preHorizSpeed - postHorizSpeed; + float damage = (float)(speedLost * 10.0 - 3.0); + + if (damage > 0.0f) + onElytraKineticDamage(damage); + } + + if (onGround) + { + bool canStandUp = true; + if (level != nullptr) + { + float halfW = bbWidth / 2.0f; + AABB* standingBB = AABB::newTemp( + x - halfW, bb->y0, z - halfW, + x + halfW, bb->y0 + 1.8, z + halfW); + AABBList* collisions = level->getCubes(shared_from_this(), standingBB, true); + canStandUp = collisions->empty(); + } + if (canStandUp) + setElytraFlying(false); + } + } + else if (abilities.flying && riding == nullptr) + + { + double ydo = yd; + float ofs = flyingSpeed; + flyingSpeed = abilities.getFlyingSpeed(); + LivingEntity::travel(xa, ya); + yd = ydo * 0.6; + flyingSpeed = ofs; + } + else + { + LivingEntity::travel(xa, ya); + } + + checkMovementStatistiscs(x - preX, y - preY, z - preZ); +} + +float Player::getSpeed() +{ + return static_cast(getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue()); +} + +void Player::checkMovementStatistiscs(double dx, double dy, double dz) +{ + + if (riding != nullptr) + { + return; + } + if (isUnderLiquid(Material::water)) + { + int distance = static_cast(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 = static_cast(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 += static_cast(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 = static_cast(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 != nullptr) + { + int distance = static_cast(Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f)); + if (distance > 0) + { + if ( riding->instanceof(eTYPE_MINECART) ) + { + 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 == nullptr) + { + 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)); +#ifdef _XBOX_ONE + // 4J-PB - send the event to cause the progress bar to increase on XB1 + if (m_bAwardedOnARail==false) + { + if(dist < 500) + { + if((dist>0) && (dist%100==0)) + { + awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); + } + } + else + { + awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); + m_bAwardedOnARail=true; + } + } +#else + if ((m_bAwardedOnARail==false) && (dist >= 500)) + { + awardStat(GenericStats::onARail(), GenericStats::param_onARail(dist)); + m_bAwardedOnARail=true; + } +#endif + } + + } + else if ( riding->instanceof(eTYPE_BOAT) ) + { + distanceBoat += distance; + if( distanceBoat >= 100 ) + { + int newDistance = distanceBoat - (distanceBoat % 100); + distanceBoat -= newDistance; + awardStat(GenericStats::boatOneM(), GenericStats::param_boat(newDistance/100) ); + } + } + else if ( riding->instanceof(eTYPE_PIG) ) + { + distancePig += distance; + if( distancePig >= 100 ) + { + int newDistance = distancePig - (distancePig % 100); + distancePig -= newDistance; + awardStat(GenericStats::pigOneM(), GenericStats::param_pig(newDistance/100) ); + } + } + } + } +} +void Player::checkFallDamage(double ya, bool onGround) +{ + LivingEntity::checkFallDamage(ya, onGround); +} + + + + + +void Player::causeFallDamage(float distance) +{ + if (abilities.mayfly) return; + + if (isElytraFlying()) + { + int dmg = Mth::ceil(distance - 3.0f); + if (dmg > 0) + onElytraFallDamage(dmg); + return; + } + + if (distance >= 2) + { + distanceFall += static_cast(Math::round(distance * 100.0)); + if( distanceFall >= 100 ) + { + int newDistance = distanceFall - (distanceFall % 100); + distanceFall -= newDistance; + awardStat(GenericStats::fallOneM(), GenericStats::param_fall(newDistance/100) ); + } + } + LivingEntity::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( mob->instanceof(eTYPE_ENEMY) || 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() != nullptr && 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()); + } +} + +void Player::makeStuckInWeb() +{ + if (!abilities.flying) LivingEntity::makeStuckInWeb(); +} + +Icon *Player::getItemInHandIcon(shared_ptr item, int layer) +{ + Icon *icon = LivingEntity::getItemInHandIcon(item, layer); + if (item->id == Item::fishing_rod->id && fishing != nullptr) + { + icon = Item::fishing_rod->getEmptyIcon(); + } + else if (item->getItem()->hasMultipleSpriteLayers()) + { + return item->getItem()->getLayerIcon(item->getAuxValue(), layer); + } + else if (useItem != nullptr && 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::increaseXp(int i) +{ + increaseScore(i); + int max = INT_MAX - totalExperience; + if (i > max) + { + i = max; + } + experienceProgress += static_cast(i) / getXpNeededForNextLevel(); + totalExperience += i; + while (experienceProgress >= 1) + { + experienceProgress = (experienceProgress - 1) * getXpNeededForNextLevel(); + giveExperienceLevels(1); + experienceProgress /= getXpNeededForNextLevel(); + } +} + +void Player::giveExperienceLevels(int amount) +{ + experienceLevel += amount; + if (experienceLevel < 0) + { + experienceLevel = 0; + experienceProgress = 0; + totalExperience = 0; + } + + if (amount > 0 && experienceLevel % 5 == 0 && lastLevelUpTime < tickCount - SharedConstants::TICKS_PER_SECOND * 5.0f) + { + float vol = experienceLevel > 30 ? 1 : experienceLevel / 30.0f; + level->playEntitySound(shared_from_this(), eSoundType_RANDOM_LEVELUP, vol * 0.75f, 1); + lastLevelUpTime = tickCount; + } +} + +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; +} + +/** +* 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); + } + //if (GenericStats::itemsUsed(instance->getItem()->id)->id < 0) return; + // 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 ( (instance->getItem()->id == Item::rotten_flesh_Id) && (getFoodData()->getFoodLevel() == 0) ) + awardStat(GenericStats::ironBelly(), GenericStats::param_ironBelly()); + +} + +bool Player::mayDestroyBlockAt(int x, int y, int z) +{ + if (abilities.mayBuild) + { + return true; + } + int t = level->getTile(x, y, z); + if (t > 0) { + Tile *tile = Tile::tiles[t]; + + if (tile->material->isDestroyedByHand()) + { + return true; + } + else if (getSelectedItem() != nullptr) + { + shared_ptr carried = getSelectedItem(); + + if (carried->canDestroySpecial(tile) || carried->getDestroySpeed(tile) > 1) + { + return true; + } + } + } + return false; +} + +bool Player::mayUseItemAt(int x, int y, int z, int face, shared_ptr item) +{ + if (abilities.mayBuild) + { + return true; + } + if (item != nullptr) + { + return item->mayBePlacedInAdventureMode(); + } + return false; +} + +int Player::getExperienceReward(shared_ptr killedBy) +{ + if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) return 0; + 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; +} + +bool Player::shouldShowName() +{ + return true; +} + +void Player::restoreFrom(shared_ptr oldPlayer, bool restoreAll) +{ + if(restoreAll) + { + inventory->replaceWith(oldPlayer->inventory); + + setHealth(oldPlayer->getHealth()); + foodData = oldPlayer->foodData; + + experienceLevel = oldPlayer->experienceLevel; + totalExperience = oldPlayer->totalExperience; + experienceProgress = oldPlayer->experienceProgress; + + setScore(oldPlayer->getScore()); + portalEntranceDir = oldPlayer->portalEntranceDir; + } +#if defined(MINECRAFT_SERVER_BUILD) + else if (oldPlayer->fk_hasDeathState) + { + if (oldPlayer->fk_deathKeepInventory || level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + inventory->replaceWith(oldPlayer->inventory); + } + if (oldPlayer->fk_deathKeepLevel || level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + experienceLevel = oldPlayer->experienceLevel; + totalExperience = oldPlayer->totalExperience; + experienceProgress = oldPlayer->experienceProgress; + } + else + { + experienceLevel = oldPlayer->fk_deathNewLevel; + totalExperience = 0; + int xpNeeded = getXpNeededForNextLevel(); + experienceProgress = (xpNeeded > 0) ? (float)oldPlayer->fk_deathNewExp / (float)xpNeeded : 0.0f; + } + setScore(oldPlayer->getScore()); + } +#endif + else if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + inventory->replaceWith(oldPlayer->inventory); + + experienceLevel = oldPlayer->experienceLevel; + totalExperience = oldPlayer->totalExperience; + experienceProgress = oldPlayer->experienceProgress; + setScore(oldPlayer->getScore()); + } + 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() +{ + //PlayerTeam.formatNameForTeam(getTeam(), name); + + // If player display name is not set, return name + return m_displayName.size() > 0 ? m_displayName : name; +} + +wstring Player::getNetworkName() +{ + // 4J: We can only transmit gamertag in network packets + return name; +} + +Level *Player::getCommandSenderWorld() +{ + return level; +} + +shared_ptr Player::getEnderChestInventory() +{ + return enderChestInventory; +} + +shared_ptr Player::getCarried(int slot) +{ + if (slot == 0) return inventory->getSelected(); + return inventory->armor[slot - 1]; +} + +shared_ptr Player::getCarriedItem() +{ + return inventory->getSelected(); +} + +void Player::setEquippedSlot(int slot, shared_ptr item) +{ + inventory->armor[slot] = item; +} + +bool Player::isInvisibleTo(shared_ptr player) +{ + return isInvisible(); +} + +ItemInstanceArray Player::getEquipmentSlots() +{ + return inventory->armor; +} + +bool Player::isCapeHidden() +{ + return getPlayerFlag(FLAG_HIDE_CAPE); +} +bool Player::isElytraFlying() +{ + return getPlayerFlag(FLAG_ELYTRA_FLYING); +} + +void Player::startFireworkBoost(shared_ptr firework) +{ + int flight = 0; + if (firework != nullptr && firework->hasTag()) + { + CompoundTag *fw = firework->getTag()->getCompound(FireworksItem::TAG_FIREWORKS); + if (fw != nullptr && fw->contains(FireworksItem::TAG_FLIGHT)) + flight = fw->getByte(FireworksItem::TAG_FLIGHT); + } + m_fireworkBoostTicks = (SharedConstants::TICKS_PER_SECOND / 2) * (flight + 1) + random->nextInt(6) + random->nextInt(7); +} + +void Player::onElytraKineticDamage(float damage) +{ + hurt(DamageSource::flyIntoWall, damage); +} + +void Player::onElytraFallDamage(int amount) +{ + hurt(DamageSource::fall, (float)amount); +} + +void Player::setElytraFlying(bool flying) +{ + setPlayerFlag(FLAG_ELYTRA_FLYING, flying); + if (flying) + { + m_wasElytraFlying = false; + setSize(0.6f, 0.6f); + fallDistance = 0.0f; + m_elytraMaxY = (float)y; + } + else + { + ticksElytraFlying = 0; + + m_wasElytraFlying = true; + m_elytraFallProtectTicks = 60; + m_fireworkBoostTicks = 0; + m_elytraRocketCooldown = 0; + setSize(0.6f, 1.8f); + } +} + + + +bool Player::isPushedByWater() +{ + return !abilities.flying; +} + +Scoreboard *Player::getScoreboard() +{ + return level->getScoreboard(); +} + +Team *Player::getTeam() +{ + return getScoreboard()->getPlayersTeam(name); +} + +void Player::setAbsorptionAmount(float absorptionAmount) +{ + if (absorptionAmount < 0) absorptionAmount = 0; + getEntityData()->set(DATA_PLAYER_ABSORPTION_ID, absorptionAmount); +} + +float Player::getAbsorptionAmount() +{ + return getEntityData()->getFloat(DATA_PLAYER_ABSORPTION_ID); +} + +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"; + case eDefaultSkins_Skin8: + return TN_MOB_ALEX; // 4J - was L"/mob/alex.png"; + case eDefaultSkins_Skin9: + return TN_MOB_ALEX1; // 4J - was L"/mob/alex1.png"; + case eDefaultSkins_Skin10: + return TN_MOB_ALEX2; // 4J - was L"/mob/alex2.png"; + case eDefaultSkins_Skin11: + return TN_MOB_ALEX3; // 4J - was L"/mob/alex3.png"; + case eDefaultSkins_Skin12: + return TN_MOB_ALEX4; // 4J - was L"/mob/alex4.png"; + case eDefaultSkins_Skin13: + return TN_MOB_ALEX5; // 4J - was L"/mob/alex5.png"; + case eDefaultSkins_Skin14: + return TN_MOB_ALEX6; // 4J - was L"/mob/alex6.png"; + case eDefaultSkins_Skin15: + return TN_MOB_ALEX7; // 4J - was L"/mob/alex7.png"; + case eDefaultSkins_Skin16: + return TN_MOB_DEVALEX; // 4J - was L"/mob/DevAlex.png"; + case eDefaultSkins_Skin17: + return TN_MOB_DEVSTEVE; // 4J - was L"/mob/DevSteve.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 static_cast(std::hash{}(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::wooden_door_Id: + case Tile::stone_button_Id: + case Tile::wooden_button_Id: + case Tile::lever_Id: + case Tile::fence_gate_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::lit_furnace_Id: + case Tile::dispenser_Id: + case Tile::brewing_stand_Id: + case Tile::enchanting_table_Id: + case Tile::crafting_table_Id: + case Tile::anvil_Id: + case Tile::ender_chest_Id: + allowed = true; + break; + } + } + + if(!allowed && getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CannotBuild) == 0) + { + switch(tile->id) + { + case Tile::wooden_door_Id: + case Tile::stone_button_Id: + case Tile::wooden_button_Id: + case Tile::lever_Id: + case Tile::fence_gate_Id: + case Tile::trapdoor_Id: + case Tile::chest_Id: + case Tile::furnace_Id: + case Tile::lit_furnace_Id: + case Tile::dispenser_Id: + case Tile::brewing_stand_Id: + case Tile::enchanting_table_Id: + case Tile::crafting_table_Id: + case Tile::anvil_Id: + case Tile::ender_chest_Id: + allowed = false; + break; + default: + allowed = true; + break; + } + } + } + + return allowed; +} + +bool Player::isAllowedToUse(shared_ptr item) +{ + bool allowed = true; + if(item != nullptr && 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::mushroom_stew_Id: + case Item::apple_Id: + case Item::bread_Id: + case Item::porkchop_Id: + case Item::cooked_porkchop_Id: + case Item::golden_apple_Id: + case Item::fish_Id: + case Item::cooked_fish_Id: + case Item::cookie_Id: + case Item::cooked_beef_Id: + case Item::beef_Id: + case Item::cooked_chicken_Id: + case Item::chicken_Id: + case Item::melon_block_Id: + case Item::rotten_flesh_Id: + // bow + case Item::bow_Id: + case Item::diamond_sword_Id: + case Item::golden_sword_Id: + case Item::iron_sword_Id: + case Item::stone_sword_Id: + case Item::wooden_sword_Id: + allowed = true; + break; + } + } + + return allowed; +} + +bool Player::isAllowedToInteract(shared_ptr target) +{ + bool allowed = true; + if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) + { + if (target->instanceof(eTYPE_MINECART)) + { + if (getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) == 0) + { + shared_ptr minecart = dynamic_pointer_cast( target ); + if (minecart->getType() == Minecart::TYPE_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==nullptr && !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 != nullptr || app.IsFileInMemoryTextures(customTextureUrl)) + { + m_bCheckedForModelParts=true; + } + if(m_ppAdditionalModelParts == nullptr && !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!=nullptr) + { + 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; +} + +vector *Player::GetSkinOffsets() +{ + if(m_ppSkinOffsets==nullptr && !m_bCheckedForSkinOffsets) + { + bool hasCustomTexture = !customTextureUrl.empty(); + bool customTextureIsDefaultSkin = customTextureUrl.substr(0,3).compare(L"def") == 0; + + // see if we can find the parts + m_ppSkinOffsets=app.GetSkinOffsets(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_ppSkinOffsets != nullptr || app.IsFileInMemoryTextures(customTextureUrl)) + { + m_bCheckedForSkinOffsets=true; + } + if(m_ppSkinOffsets == nullptr && !m_bCheckedDLCForSkinOffsets) + { + m_bCheckedDLCForSkinOffsets = true; + + // we don't have the data from the dlc skin yet + app.DebugPrintf("m_bCheckedForModelOffsets Couldn't get skin offsets for skin %X\n",m_dwSkinId); + + // do we have it from the DLC pack? + DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(this->customTextureUrl); + + if(pDLCSkinFile!=nullptr) + { + DWORD dwOffsetC=pDLCSkinFile->getOffsetsCount(); + if(dwOffsetC!=0) + { + app.DebugPrintf("m_bCheckedForSkinOffsets Got skin offsets from DLCskin for skin %X\n",m_dwSkinId); + m_ppSkinOffsets=app.SetSkinOffsets(m_dwSkinId,pDLCSkinFile->getOffsets()); + } + + m_bCheckedForSkinOffsets=true; + } + } + } + return m_ppSkinOffsets; +} + +int Player::GetModelTypeFromAnimBitmask(unsigned int animBitmask) +{ + if (animBitmask&(1< 8 && textureId < 18) return 2; + else if (textureId == 18) return 1; + else return 0; +} + +void Player::SetAdditionalModelParts(vector *ppAdditionalModelParts) +{ + m_ppAdditionalModelParts=ppAdditionalModelParts; +} + +void Player::SetSkinOffsets(vector *ppSkinOffsets) +{ + m_ppSkinOffsets=ppSkinOffsets; +} + +#if defined(__PS3__) || defined(__ORBIS__) + +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 + +bool Player::isSpectator() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/Player.h b/Minecraft.World/Player.h index 19bef7bd..2f77d917 100644 --- a/Minecraft.World/Player.h +++ b/Minecraft.World/Player.h @@ -83,7 +83,7 @@ protected: public: int ticksElytraFlying; - float rotateElytraX; + float rotateElytraX; float rotateElytraY; float rotateElytraZ; float m_elytraImpactYd; @@ -95,7 +95,7 @@ public: int m_fireworkBoostTicks; int m_elytraRocketCooldown; public: - void startFireworkBoost(shared_ptr firework); + void startFireworkBoost(shared_ptr firework); bool isElytraFlying(); virtual void setElytraFlying(bool flying); @@ -324,7 +324,7 @@ private: public: /** - * + * * @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 @@ -569,6 +569,11 @@ public: vector *GetSkinOffsets(); void SetSkinOffsets(vector *ppSkinOffsets); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); + #if defined(__PS3__) || defined(__ORBIS__) enum ePlayerNameValidState { @@ -595,13 +600,12 @@ private: struct PlayerKeyHash { - inline int operator() (const shared_ptr k) const + inline int operator() (const shared_ptr k) const { return Player::hash_fnct (k); } }; struct PlayerKeyEq { - inline bool operator() (const shared_ptr x, const shared_ptr y) const + inline bool operator() (const shared_ptr x, const shared_ptr y) const { return Player::eq_test (x, y); } }; - diff --git a/Minecraft.World/PotionItem.cpp b/Minecraft.World/PotionItem.cpp index 4c5bcdbe..b82fd856 100644 --- a/Minecraft.World/PotionItem.cpp +++ b/Minecraft.World/PotionItem.cpp @@ -416,4 +416,21 @@ vector > *PotionItem::getUniquePotionValues() } } return &s_uniquePotionValues; -} \ No newline at end of file +} + +int PotionItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + { + if (MACRO_POTION_IS_SPLASH(itemInstance->getAuxValue())) + { + return IDS_TOOLTIPS_THROW; + } + else + { + return IDS_TOOLTIPS_DRINK; + } + } + + return 0; +} diff --git a/Minecraft.World/PotionItem.h b/Minecraft.World/PotionItem.h index 4a43505f..c311ef13 100644 --- a/Minecraft.World/PotionItem.h +++ b/Minecraft.World/PotionItem.h @@ -51,7 +51,9 @@ public: // 4J Stu - Based loosely on a function that gets added in java much later on (1.3) static vector > *getUniquePotionValues(); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; private: // 4J Stu - Added to support function above, different from Java implementation static vector > s_uniquePotionValues; -}; \ No newline at end of file +}; diff --git a/Minecraft.World/RailTile.cpp b/Minecraft.World/RailTile.cpp index 798d248c..e752df5a 100644 --- a/Minecraft.World/RailTile.cpp +++ b/Minecraft.World/RailTile.cpp @@ -33,4 +33,9 @@ void RailTile::updateState(Level *level, int x, int y, int z, int data, int dir, updateDir(level, x, y, z, false); } } +} + +int RailTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return bUseItemOn ? IDS_TOOLTIPS_PLACE : 0; } \ No newline at end of file diff --git a/Minecraft.World/RailTile.h b/Minecraft.World/RailTile.h index eacbf05b..cb291c02 100644 --- a/Minecraft.World/RailTile.h +++ b/Minecraft.World/RailTile.h @@ -9,12 +9,14 @@ class RailTile : public BaseRailTile private: Icon *iconTurn; -public: + public: RailTile(int id); Icon *getTexture(int face, int data); void registerIcons(IconRegister *iconRegister); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; + protected: void updateState(Level *level, int x, int y, int z, int data, int dir, int type); }; \ No newline at end of file diff --git a/Minecraft.World/RedStoneOreTile.cpp b/Minecraft.World/RedStoneOreTile.cpp index 411bc474..bcd08d53 100644 --- a/Minecraft.World/RedStoneOreTile.cpp +++ b/Minecraft.World/RedStoneOreTile.cpp @@ -125,4 +125,9 @@ bool RedStoneOreTile::shouldTileTick(Level *level, int x,int y,int z) shared_ptr RedStoneOreTile::getSilkTouchItemInstance(int data) { return std::make_shared(Tile::redStoneOre); +} + +int RedStoneOreTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return bUseItemOn ? IDS_TOOLTIPS_USE : 0; } \ No newline at end of file diff --git a/Minecraft.World/RedStoneOreTile.h b/Minecraft.World/RedStoneOreTile.h index 2ff80ed5..fe986311 100644 --- a/Minecraft.World/RedStoneOreTile.h +++ b/Minecraft.World/RedStoneOreTile.h @@ -31,4 +31,6 @@ private: void poofParticles(Level *level, int x, int y, int z); protected: virtual shared_ptr getSilkTouchItemInstance(int data); + + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const override; }; diff --git a/Minecraft.World/SeedItem.cpp b/Minecraft.World/SeedItem.cpp index 87211d8b..2dd33076 100644 --- a/Minecraft.World/SeedItem.cpp +++ b/Minecraft.World/SeedItem.cpp @@ -23,7 +23,7 @@ bool SeedItem::useOn(shared_ptr instance, shared_ptr playe int targetType = level->getTile(x, y, z); - if (targetType == targetLand && level->isEmptyTile(x, y + 1, z)) + if (targetType == targetLand && level->isEmptyTile(x, y + 1, z)) { if(!bTestUseOnOnly) { @@ -33,4 +33,18 @@ bool SeedItem::useOn(shared_ptr instance, shared_ptr playe return true; } return false; -} \ No newline at end of file +} + +int SeedItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem && level != nullptr) + { + int targetType = level->getTile(x, y, z); + int above = level->getTile(x, y + 1, z); + + if (this->targetLand && above == 0) + return IDS_TOOLTIPS_PLANT; + } + + return 0; +} diff --git a/Minecraft.World/SeedItem.h b/Minecraft.World/SeedItem.h index c16a76ce..ab356c2f 100644 --- a/Minecraft.World/SeedItem.h +++ b/Minecraft.World/SeedItem.h @@ -3,7 +3,7 @@ using namespace std; #include "Item.h" -class SeedItem : public Item +class SeedItem : public Item { private: int resultId; @@ -13,4 +13,6 @@ public: SeedItem(int id, int resultId, int targetLand); virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/Sheep.cpp b/Minecraft.World/Sheep.cpp index 8fe23825..47f7490f 100644 --- a/Minecraft.World/Sheep.cpp +++ b/Minecraft.World/Sheep.cpp @@ -96,7 +96,7 @@ void Sheep::registerAttributes() getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.23f); } -void Sheep::defineSynchedData() +void Sheep::defineSynchedData() { Animal::defineSynchedData(); @@ -239,31 +239,31 @@ bool Sheep::mobInteract(shared_ptr player) return Animal::mobInteract(player); } -void Sheep::addAdditonalSaveData(CompoundTag *tag) +void Sheep::addAdditonalSaveData(CompoundTag *tag) { Animal::addAdditonalSaveData(tag); tag->putBoolean(L"Sheared", isSheared()); tag->putByte(L"Color", static_cast(getColor())); } -void Sheep::readAdditionalSaveData(CompoundTag *tag) +void Sheep::readAdditionalSaveData(CompoundTag *tag) { Animal::readAdditionalSaveData(tag); setSheared(tag->getBoolean(L"Sheared")); setColor((int) tag->getByte(L"Color")); } -int Sheep::getAmbientSound() +int Sheep::getAmbientSound() { return eSoundType_MOB_SHEEP_AMBIENT; } -int Sheep::getHurtSound() +int Sheep::getHurtSound() { return eSoundType_MOB_SHEEP_AMBIENT; } -int Sheep::getDeathSound() +int Sheep::getDeathSound() { return eSoundType_MOB_SHEEP_AMBIENT; } @@ -273,51 +273,51 @@ void Sheep::playStepSound(int xt, int yt, int zt, int t) playSound(eSoundType_MOB_SHEEP_STEP, 0.15f, 1); } -int Sheep::getColor() +int Sheep::getColor() { return (entityData->getByte(DATA_WOOL_ID) & 0x0f); } -void Sheep::setColor(int color) +void Sheep::setColor(int color) { byte current = entityData->getByte(DATA_WOOL_ID); entityData->set(DATA_WOOL_ID, static_cast((current & 0xf0) | (color & 0x0f))); } -bool Sheep::isSheared() +bool Sheep::isSheared() { return (entityData->getByte(DATA_WOOL_ID) & 0x10) != 0; } -void Sheep::setSheared(bool value) +void Sheep::setSheared(bool value) { byte current = entityData->getByte(DATA_WOOL_ID); - if (value) + if (value) { entityData->set(DATA_WOOL_ID, static_cast(current | 0x10)); - } - else + } + else { entityData->set(DATA_WOOL_ID, static_cast(current & ~0x10)); } } -int Sheep::getSheepColor(Random *random) +int Sheep::getSheepColor(Random *random) { int nextInt = random->nextInt(100); - if (nextInt < 5) + if (nextInt < 5) { return 15 - DyePowderItem::BLACK; } - if (nextInt < 10) + if (nextInt < 10) { return 15 - DyePowderItem::GRAY; } - if (nextInt < 15) + if (nextInt < 15) { return 15 - DyePowderItem::SILVER; } - if (nextInt < 18) + if (nextInt < 18) { return 15 - DyePowderItem::BROWN; } @@ -386,3 +386,78 @@ int Sheep::getDyeColor(shared_ptr animal) { return 15 - dynamic_pointer_cast(animal)->getColor(); } + +int Sheep::getAttackTooltipId(std::shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int Sheep::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + + switch (heldItemId) + { + case Item::name_tag_Id: + return IDS_TOOLTIPS_NAME; + + case Item::lead_Id: + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + break; + + case Item::dye_Id: + { + // convert to tile-based color value (0 is white instead of black) + int newColor = ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue()); + + // can only use a dye on sheep that haven't been sheared + if (!(this->isSheared() && this->getColor() != newColor)) + { + return IDS_TOOLTIPS_DYE; + } + } + break; + case Item::shears_Id: + { + // can only shear a sheep that hasn't been sheared + if (!this->isBaby() && !this->isSheared()) + { + return IDS_TOOLTIPS_SHEAR; + } + } + + break; + default: + { + if (!this->isBaby() && !this->isInLove() && (this->getAge() == 0) && this->isFood(heldItem)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + break; + + case -1: + break; // 4J-JEV: Empty hand. + } + + return 0; +} diff --git a/Minecraft.World/Sheep.h b/Minecraft.World/Sheep.h index 16ecfb4c..cb6ea9be 100644 --- a/Minecraft.World/Sheep.h +++ b/Minecraft.World/Sheep.h @@ -81,6 +81,10 @@ public: virtual void ate(); MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); private: int getOffspringColor(shared_ptr animal, shared_ptr partner); diff --git a/Minecraft.World/SnowballItem.cpp b/Minecraft.World/SnowballItem.cpp index afb190d8..1e664b50 100644 --- a/Minecraft.World/SnowballItem.cpp +++ b/Minecraft.World/SnowballItem.cpp @@ -20,4 +20,9 @@ shared_ptr SnowballItem::use(shared_ptr instance, Le level->playEntitySound((shared_ptr ) player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) level->addEntity(std::make_shared(level, player)); return instance; -} \ No newline at end of file +} + +int SnowballItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_THROW; +} diff --git a/Minecraft.World/SnowballItem.h b/Minecraft.World/SnowballItem.h index bf2d20cb..f1a96f86 100644 --- a/Minecraft.World/SnowballItem.h +++ b/Minecraft.World/SnowballItem.h @@ -9,4 +9,7 @@ public: SnowballItem(int id); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; + +}; diff --git a/Minecraft.World/Tile.h b/Minecraft.World/Tile.h index a29d889f..2a67bc1d 100644 --- a/Minecraft.World/Tile.h +++ b/Minecraft.World/Tile.h @@ -871,6 +871,28 @@ public: // AP - added this function so we can generate the faceFlags for a block in a single fast function int getFaceFlags(LevelSource *level, int x, int y, int z); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const + { + return 0; + } + + virtual int getInteractTooltipId(Level* level, + int x, int y, int z, + std::shared_ptr player, + bool bUseItemOn) const + { + return 0; + } + + virtual int getAttackTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const + { + return IDS_TOOLTIPS_MINE; + } }; class stoneBrick : public Tile {}; diff --git a/Minecraft.World/TileItem.cpp b/Minecraft.World/TileItem.cpp index 3e73c56e..4694b607 100644 --- a/Minecraft.World/TileItem.cpp +++ b/Minecraft.World/TileItem.cpp @@ -17,13 +17,13 @@ using namespace std; #include -TileItem::TileItem(int id) : Item(id) +TileItem::TileItem(int id) : Item(id) { this->tileId = id + 256; itemIcon = nullptr; } -int TileItem::getTileId() +int TileItem::getTileId() { return tileId; } @@ -46,7 +46,7 @@ Icon *TileItem::getIcon(int auxValue) return Tile::tiles[tileId]->getTexture(Facing::UP, auxValue); } -bool TileItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +bool TileItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { // 4J-PB - Adding a test only version to allow tooltips to be displayed int currentTile = level->getTile(x, y, z); @@ -57,7 +57,7 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe else if (currentTile == Tile::vine_Id || currentTile == Tile::tallgrass_Id || currentTile == Tile::deadbush_Id) { } - else + else { if (face == 0) y--; if (face == 1) y++; @@ -75,7 +75,7 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe int undertile = level->getTile(x,y-1,z); // For 'BodyGuard' achievement. - if (level->mayPlace(tileId, x, y, z, false, face, player, instance)) + if (level->mayPlace(tileId, x, y, z, false, face, player, instance)) { if(!bTestUseOnOnly) { @@ -83,7 +83,7 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe // 4J - Adding this from 1.6 int itemValue = getLevelDataForAuxValue(instance->getAuxValue()); int dataValue = Tile::tiles[tileId]->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, itemValue); - if (level->setTileAndData(x, y, z, tileId, dataValue, Tile::UPDATE_ALL)) + if (level->setTileAndData(x, y, z, tileId, dataValue, Tile::UPDATE_ALL)) { // 4J-JEV: Snow/Iron Golems do not have owners apparently. int newTileId = level->getTile(x,y,z); @@ -125,7 +125,7 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe // char szPlaceSoundName[256]; // char szStepSoundName[256]; // Minecraft *pMinecraft = Minecraft::GetInstance(); - // + // // if(iPlaceSound==-1) // { // strcpy(szPlaceSoundName,"nullptr"); @@ -162,7 +162,7 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe } -bool TileItem::mayPlace(Level *level, int x, int y, int z, int face, shared_ptr player, shared_ptr item) +bool TileItem::mayPlace(Level *level, int x, int y, int z, int face, shared_ptr player, shared_ptr item) { int currentTile = level->getTile(x, y, z); if (currentTile == Tile::snow_layer_Id) @@ -188,25 +188,25 @@ int TileItem::getColor(int itemAuxValue, int spriteLayer) return Tile::tiles[tileId]->getColor(); } -unsigned int TileItem::getDescriptionId(shared_ptr instance) +unsigned int TileItem::getDescriptionId(shared_ptr instance) { return Tile::tiles[tileId]->getDescriptionId(); } -unsigned int TileItem::getDescriptionId(int iData /*= -1*/) +unsigned int TileItem::getDescriptionId(int iData /*= -1*/) { return Tile::tiles[tileId]->getDescriptionId(iData); } -unsigned int TileItem::getUseDescriptionId(shared_ptr instance) +unsigned int TileItem::getUseDescriptionId(shared_ptr instance) { return Tile::tiles[tileId]->getUseDescriptionId(); } -unsigned int TileItem::getUseDescriptionId() +unsigned int TileItem::getUseDescriptionId() { return Tile::tiles[tileId]->getUseDescriptionId(); } @@ -219,3 +219,21 @@ void TileItem::registerIcons(IconRegister *iconRegister) itemIcon = iconRegister->registerIcon(iconName); } } + +int TileItem::getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const +{ + if (this->tileId > 0 && Tile::tiles[this->tileId] != nullptr) + { + int tileTooltip = Tile::tiles[this->tileId]->getUseTooltipId(itemInstance, player, level, x, y, z, bUseItem); + if (tileTooltip != 0) + { + return tileTooltip; + } + } + + return IDS_TOOLTIPS_PLACE; +} diff --git a/Minecraft.World/TileItem.h b/Minecraft.World/TileItem.h index ac341acc..2cc2009e 100644 --- a/Minecraft.World/TileItem.h +++ b/Minecraft.World/TileItem.h @@ -11,13 +11,13 @@ class TileItem : public Item public: static const int _class = 0; using Item::getColor; -private: +private: int tileId; Icon *itemIcon; public: - TileItem(int id); - + TileItem(int id); + virtual int getTileId(); //@Override @@ -41,4 +41,10 @@ public: //@Override virtual void registerIcons(IconRegister *iconRegister); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, + std::shared_ptr player, + Level* level, + int x, int y, int z, + bool bUseItem) const override; }; diff --git a/Minecraft.World/TrapDoorTile.cpp b/Minecraft.World/TrapDoorTile.cpp index 97ea849a..b75d1064 100644 --- a/Minecraft.World/TrapDoorTile.cpp +++ b/Minecraft.World/TrapDoorTile.cpp @@ -240,4 +240,9 @@ bool TrapDoorTile::attachesTo(int id) Tile *tile = Tile::tiles[id]; return tile != nullptr && (tile->material->isSolidBlocking() && tile->isCubeShaped()) || tile == Tile::glowstone || (dynamic_cast(tile) != nullptr) || (dynamic_cast(tile) != nullptr); -} \ No newline at end of file +} + +int TrapDoorTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/TrapDoorTile.h b/Minecraft.World/TrapDoorTile.h index 9629c50a..cd608b71 100644 --- a/Minecraft.World/TrapDoorTile.h +++ b/Minecraft.World/TrapDoorTile.h @@ -87,6 +87,8 @@ public: public: static bool isOpen(int data); + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; + private: static bool attachesTo(int id); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Villager.cpp b/Minecraft.World/Villager.cpp index 90ade912..bb81222d 100644 --- a/Minecraft.World/Villager.cpp +++ b/Minecraft.World/Villager.cpp @@ -788,7 +788,22 @@ void Villager::thunderHit(const LightningBolt *lightningBolt) if (this->isPersistenceRequired()) witch->setPersistenceRequired(); - + level->addEntity(witch); remove(); } + +int Villager::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_HIT; +} + +int Villager::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + if (!this->isBaby()) + return IDS_TOOLTIPS_TRADE; + + return 0; +} diff --git a/Minecraft.World/Villager.h b/Minecraft.World/Villager.h index f08a028b..f4aaa89f 100644 --- a/Minecraft.World/Villager.h +++ b/Minecraft.World/Villager.h @@ -148,4 +148,9 @@ public: virtual bool canBeLeashed(); virtual wstring getDisplayName(); virtual void thunderHit(const LightningBolt *lightningBolt); -}; \ No newline at end of file + + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); +}; diff --git a/Minecraft.World/WaterLilyTileItem.cpp b/Minecraft.World/WaterLilyTileItem.cpp index 978a611f..37e4c4ce 100644 --- a/Minecraft.World/WaterLilyTileItem.cpp +++ b/Minecraft.World/WaterLilyTileItem.cpp @@ -26,11 +26,11 @@ bool WaterLilyTileItem::TestUse(shared_ptr itemInstance, Level *le return false; } if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) - { + { delete hr; return false; } - + delete hr; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0 && level->isEmptyTile(xt, yt + 1, zt)) { @@ -60,11 +60,11 @@ shared_ptr WaterLilyTileItem::use(shared_ptr itemIns return itemInstance; } if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) - { + { delete hr; return itemInstance; } - + delete hr; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0 && level->isEmptyTile(xt, yt + 1, zt)) { @@ -85,4 +85,12 @@ shared_ptr WaterLilyTileItem::use(shared_ptr itemIns int WaterLilyTileItem::getColor(int data, int spriteLayer) { return Tile::waterLily->getColor(data); -} \ No newline at end of file +} + +int WaterLilyTileItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + if (bUseItem) + return IDS_TOOLTIPS_PLACE; + + return 0; +} diff --git a/Minecraft.World/WaterLilyTileItem.h b/Minecraft.World/WaterLilyTileItem.h index c107578f..8fc198ee 100644 --- a/Minecraft.World/WaterLilyTileItem.h +++ b/Minecraft.World/WaterLilyTileItem.h @@ -11,4 +11,6 @@ public: virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual int getColor(int data, int spriteLayer); + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; }; diff --git a/Minecraft.World/WeaponItem.cpp b/Minecraft.World/WeaponItem.cpp index 67b887af..1ee8b541 100644 --- a/Minecraft.World/WeaponItem.cpp +++ b/Minecraft.World/WeaponItem.cpp @@ -37,7 +37,7 @@ float WeaponItem::getDestroySpeed(shared_ptr itemInstance, Tile *t return 1.0f; } -bool WeaponItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) +bool WeaponItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) { itemInstance->hurtAndBreak(1, attacker); return true; @@ -58,7 +58,7 @@ bool WeaponItem::isHandEquipped() UseAnim WeaponItem::getUseAnimation(shared_ptr itemInstance) { return UseAnim_block; -} +} int WeaponItem::getUseDuration(shared_ptr itemInstance) { @@ -102,4 +102,9 @@ attrAttrModMap *WeaponItem::getDefaultAttributeModifiers() result->insert(attrAttrModMap::value_type( SharedMonsterAttributes::ATTACK_DAMAGE->getId(), new AttributeModifier(eModifierId_ITEM_BASEDAMAGE, damage, AttributeModifier::OPERATION_ADDITION) ) ); return result; -} \ No newline at end of file +} + +int WeaponItem::getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const +{ + return IDS_TOOLTIPS_BLOCK; +} diff --git a/Minecraft.World/WeaponItem.h b/Minecraft.World/WeaponItem.h index 54cb2f2d..87a7bd00 100644 --- a/Minecraft.World/WeaponItem.h +++ b/Minecraft.World/WeaponItem.h @@ -25,4 +25,6 @@ public: const Tier *getTier(); bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); attrAttrModMap *getDefaultAttributeModifiers(); -}; \ No newline at end of file + + virtual int getUseTooltipId(std::shared_ptr itemInstance, std::shared_ptr player, Level* level, int x, int y, int z, bool bUseItem) const; +}; diff --git a/Minecraft.World/Wolf.cpp b/Minecraft.World/Wolf.cpp index 306bdf35..6680212b 100644 --- a/Minecraft.World/Wolf.cpp +++ b/Minecraft.World/Wolf.cpp @@ -96,7 +96,7 @@ void Wolf::serverAiMobStep() entityData->set(DATA_HEALTH_ID, getHealth()); } -void Wolf::defineSynchedData() +void Wolf::defineSynchedData() { TamableAnimal::defineSynchedData(); entityData->define(DATA_HEALTH_ID, getHealth()); @@ -109,7 +109,7 @@ void Wolf::playStepSound(int xt, int yt, int zt, int t) playSound(eSoundType_MOB_WOLF_STEP, 0.15f, 1); } -void Wolf::addAdditonalSaveData(CompoundTag *tag) +void Wolf::addAdditonalSaveData(CompoundTag *tag) { TamableAnimal::addAdditonalSaveData(tag); @@ -117,7 +117,7 @@ void Wolf::addAdditonalSaveData(CompoundTag *tag) tag->putByte(L"CollarColor", static_cast(getCollarColor())); } -void Wolf::readAdditionalSaveData(CompoundTag *tag) +void Wolf::readAdditionalSaveData(CompoundTag *tag) { TamableAnimal::readAdditionalSaveData(tag); @@ -125,15 +125,15 @@ void Wolf::readAdditionalSaveData(CompoundTag *tag) if (tag->contains(L"CollarColor")) setCollarColor(tag->getByte(L"CollarColor")); } -int Wolf::getAmbientSound() +int Wolf::getAmbientSound() { - if (isAngry()) + if (isAngry()) { return eSoundType_MOB_WOLF_GROWL; } - if (random->nextInt(3) == 0) + if (random->nextInt(3) == 0) { - if (isTame() && entityData->getFloat(DATA_HEALTH_ID) < 10) + if (isTame() && entityData->getFloat(DATA_HEALTH_ID) < 10) { return eSoundType_MOB_WOLF_WHINE; } @@ -142,31 +142,31 @@ int Wolf::getAmbientSound() return eSoundType_MOB_WOLF_BARK; } -int Wolf::getHurtSound() +int Wolf::getHurtSound() { return eSoundType_MOB_WOLF_HURT; } -int Wolf::getDeathSound() +int Wolf::getDeathSound() { return eSoundType_MOB_WOLF_DEATH; } -float Wolf::getSoundVolume() +float Wolf::getSoundVolume() { return 0.4f; } -int Wolf::getDeathLoot() +int Wolf::getDeathLoot() { return -1; } -void Wolf::aiStep() +void Wolf::aiStep() { TamableAnimal::aiStep(); - if (!level->isClientSide && m_isWet && !isShaking && !isPathFinding() && onGround) + if (!level->isClientSide && m_isWet && !isShaking && !isPathFinding() && onGround) { isShaking = true; shakeAnim = 0; @@ -176,37 +176,37 @@ void Wolf::aiStep() } } -void Wolf::tick() +void Wolf::tick() { TamableAnimal::tick(); interestedAngleO = interestedAngle; - if (isInterested()) + if (isInterested()) { interestedAngle = interestedAngle + (1 - interestedAngle) * 0.4f; - } - else + } + else { interestedAngle = interestedAngle + (0 - interestedAngle) * 0.4f; } - if (isInterested()) + if (isInterested()) { lookTime = 10; } - if (isInWaterOrRain()) + if (isInWaterOrRain()) { m_isWet = true; isShaking = false; shakeAnim = 0; shakeAnimO = 0; - } - else if (m_isWet || isShaking) + } + else if (m_isWet || isShaking) { - if (isShaking) + if (isShaking) { - if (shakeAnim == 0) + if (shakeAnim == 0) { playSound(eSoundType_MOB_WOLF_SHAKE, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); } @@ -214,7 +214,7 @@ void Wolf::tick() shakeAnimO = shakeAnim; shakeAnim += 0.05f; - if (shakeAnimO >= 2) + if (shakeAnimO >= 2) { m_isWet = false; isShaking = false; @@ -222,11 +222,11 @@ void Wolf::tick() shakeAnim = 0; } - if (shakeAnim > 0.4f) + if (shakeAnim > 0.4f) { float yt = static_cast(bb->y0); int shakeCount = static_cast(Mth::sin((shakeAnim - 0.4f) * PI) * 7.0f); - for (int i = 0; i < shakeCount; i++) + for (int i = 0; i < shakeCount; i++) { float xo = (random->nextFloat() * 2 - 1) * bbWidth * 0.5f; float zo = (random->nextFloat() * 2 - 1) * bbWidth * 0.5f; @@ -237,54 +237,54 @@ void Wolf::tick() } } -bool Wolf::isWet() +bool Wolf::isWet() { return m_isWet; } -float Wolf::getWetShade(float a) +float Wolf::getWetShade(float a) { return 0.75f + ((shakeAnimO + (shakeAnim - shakeAnimO) * a) / 2.0f) * 0.25f; } -float Wolf::getBodyRollAngle(float a, float offset) +float Wolf::getBodyRollAngle(float a, float offset) { float progress = ((shakeAnimO + (shakeAnim - shakeAnimO) * a) + offset) / 1.8f; - if (progress < 0) + if (progress < 0) { progress = 0; - } - else if (progress > 1) + } + else if (progress > 1) { progress = 1; } return Mth::sin(progress * PI) * Mth::sin(progress * PI * 11.0f) * 0.15f * PI; } -float Wolf::getHeadRollAngle(float a) +float Wolf::getHeadRollAngle(float a) { return (interestedAngleO + (interestedAngle - interestedAngleO) * a) * 0.15f * PI; } -float Wolf::getHeadHeight() +float Wolf::getHeadHeight() { return bbHeight * 0.8f; } -int Wolf::getMaxHeadXRot() +int Wolf::getMaxHeadXRot() { - if (isSitting()) + if (isSitting()) { return 20; } return TamableAnimal::getMaxHeadXRot(); } -bool Wolf::hurt(DamageSource *source, float dmg) +bool Wolf::hurt(DamageSource *source, float dmg) { // 4J: Protect owned wolves from untrusted players if (isTame()) - { + { shared_ptr entity = source->getDirectEntity(); if (entity != nullptr && entity->instanceof(eTYPE_PLAYER)) { @@ -296,7 +296,7 @@ bool Wolf::hurt(DamageSource *source, float dmg) if (isInvulnerable()) return false; shared_ptr sourceEntity = source->getEntity(); sitGoal->wantToSit(false); - if (sourceEntity != nullptr && !(sourceEntity->instanceof(eTYPE_PLAYER) || sourceEntity->instanceof(eTYPE_ARROW))) + if (sourceEntity != nullptr && !(sourceEntity->instanceof(eTYPE_PLAYER) || sourceEntity->instanceof(eTYPE_ARROW))) { // Take half damage from non-players and arrows dmg = (dmg + 1) / 2; @@ -324,7 +324,7 @@ void Wolf::setTame(bool value) } } -void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool bSetSitting) +void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool bSetSitting) { setTame(true); setPath(nullptr); @@ -338,11 +338,11 @@ void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool b spawnTamingParticles(bDisplayTamingParticles); } -bool Wolf::mobInteract(shared_ptr player) +bool Wolf::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); - if (isTame()) + if (isTame()) { if (item != nullptr) { @@ -357,13 +357,13 @@ bool Wolf::mobInteract(shared_ptr player) if (player->abilities.instabuild==false) { item->count--; - if (item->count <= 0) + if (item->count <= 0) { player->inventory->setItem(player->inventory->selected, nullptr); } } return true; - } + } } else if (item->id == Item::dye_Id) { @@ -395,7 +395,7 @@ bool Wolf::mobInteract(shared_ptr player) } else { - if (item != nullptr && item->id == Item::bone->id && !isAngry()) + if (item != nullptr && item->id == Item::bone->id && !isAngry()) { // 4J-PB - don't lose the bone in creative mode if (player->abilities.instabuild==false) @@ -407,9 +407,9 @@ bool Wolf::mobInteract(shared_ptr player) } } - if (!level->isClientSide) + if (!level->isClientSide) { - if (random->nextInt(3) == 0) + if (random->nextInt(3) == 0) { // 4J : WESTY: Added for new acheivements. player->awardStat(GenericStats::tamedEntity(eTYPE_WOLF),GenericStats::param_tamedEntity(eTYPE_WOLF)); @@ -418,8 +418,8 @@ bool Wolf::mobInteract(shared_ptr player) tame(player->getUUID(),true,true); level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_SUCCEEDED); - } - else + } + else { spawnTamingParticles(false); level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_FAILED); @@ -438,15 +438,15 @@ bool Wolf::mobInteract(shared_ptr player) return TamableAnimal::mobInteract(player); } -void Wolf::handleEntityEvent(byte id) +void Wolf::handleEntityEvent(byte id) { if (id == EntityEvent::SHAKE_WETNESS) { isShaking = true; shakeAnim = 0; shakeAnimO = 0; - } - else + } + else { TamableAnimal::handleEntityEvent(id); } @@ -454,11 +454,11 @@ void Wolf::handleEntityEvent(byte id) float Wolf::getTailAngle() { - if (isAngry()) + if (isAngry()) { return 0.49f * PI; - } - else if (isTame()) + } + else if (isTame()) { return (0.55f - (MAX_HEALTH - entityData->getFloat(DATA_HEALTH_ID)) * 0.02f) * PI; } @@ -478,18 +478,18 @@ int Wolf::getMaxSpawnClusterSize() return 4; } -bool Wolf::isAngry() +bool Wolf::isAngry() { return (entityData->getByte(DATA_FLAGS_ID) & 0x02) != 0; } -void Wolf::setAngry(bool value) +void Wolf::setAngry(bool value) { byte current = entityData->getByte(DATA_FLAGS_ID); - if (value) + if (value) { entityData->set(DATA_FLAGS_ID, static_cast(current | 0x02)); - } + } else { entityData->set(DATA_FLAGS_ID, static_cast(current & ~0x02)); @@ -507,10 +507,10 @@ void Wolf::setCollarColor(int color) } // 4J-PB added for tooltips -int Wolf::GetSynchedHealth() +int Wolf::GetSynchedHealth() { return getEntityData()->getFloat(DATA_HEALTH_ID); -} +} shared_ptr Wolf::getBreedOffspring(shared_ptr target) { @@ -596,4 +596,117 @@ bool Wolf::wantsToAttack(shared_ptr target, shared_ptr player) +{ + if (player->isAllowedToAttackAnimals()) + { + return IDS_TOOLTIPS_HIT; + } + + return 0; +} + +int Wolf::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + if (this->isLeashed() && this->getLeashHolder() == player) + { + return IDS_TOOLTIPS_UNLEASH; + } + + switch (heldItemId) + { + case Item::name_tag_Id: + return IDS_TOOLTIPS_NAME; + + case Item::lead_Id: + if (!this->isLeashed()) + { + return IDS_TOOLTIPS_LEASH; + } + break; + + case Item::bone_Id: + if (!this->isAngry() && !this->isTame()) + { + return IDS_TOOLTIPS_TAME; + } + else if (equalsIgnoreCase(player->getUUID(), this->getOwnerUUID())) + { + if (this->isSitting()) + { + return IDS_TOOLTIPS_FOLLOWME; + } + else + { + return IDS_TOOLTIPS_SIT; + } + } + + break; + case Item::ender_pearl_Id: + // Use is throw, so don't change the tips for the this + break; + case Item::dye_Id: + if (this->isTame()) + { + if (ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue()) != this->getCollarColor()) + { + return IDS_TOOLTIPS_DYECOLLAR; + } + else if (this->isSitting()) + { + return IDS_TOOLTIPS_FOLLOWME; + } + else + { + return IDS_TOOLTIPS_SIT; + } + } + break; + default: + if (this->isTame()) + { + if (this->isFood(heldItem)) + { + if (this->GetSynchedHealth() < this->getMaxHealth()) + { + return IDS_TOOLTIPS_HEAL; + } + else + { + if (!this->isBaby() && !this->isInLove() && (this->getAge() == 0)) + { + return IDS_TOOLTIPS_LOVEMODE; + } + } + // break out here + break; + } + + if (equalsIgnoreCase(player->getUUID(), this->getOwnerUUID())) + { + if (this->isSitting()) + { + return IDS_TOOLTIPS_FOLLOWME; + } + else + { + return IDS_TOOLTIPS_SIT; + } + } + } + break; + } + + return 0; +} diff --git a/Minecraft.World/Wolf.h b/Minecraft.World/Wolf.h index edfd3814..b7b58fc8 100644 --- a/Minecraft.World/Wolf.h +++ b/Minecraft.World/Wolf.h @@ -83,6 +83,10 @@ public: virtual void setIsInterested(bool isInterested); virtual bool canMate(shared_ptr animal); bool isInterested(); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); protected: virtual bool removeWhenFarAway(); diff --git a/Minecraft.World/WorkbenchTile.cpp b/Minecraft.World/WorkbenchTile.cpp index cc505fc6..adc8b8f0 100644 --- a/Minecraft.World/WorkbenchTile.cpp +++ b/Minecraft.World/WorkbenchTile.cpp @@ -42,4 +42,9 @@ bool WorkbenchTile::use(Level *level, int x, int y, int z, shared_ptr pl player->startCrafting(x, y, z); //player->openFireworks(x, y, z); return true; -} \ No newline at end of file +} + +int WorkbenchTile::getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const +{ + return IDS_TOOLTIPS_USE; +} diff --git a/Minecraft.World/WorkbenchTile.h b/Minecraft.World/WorkbenchTile.h index 1e7fd4ec..73ed9318 100644 --- a/Minecraft.World/WorkbenchTile.h +++ b/Minecraft.World/WorkbenchTile.h @@ -23,4 +23,5 @@ public: public: virtual bool TestUse(); bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param -}; \ No newline at end of file + virtual int getInteractTooltipId(Level* level, int x, int y, int z, std::shared_ptr player, bool bUseItemOn) const; +}; diff --git a/Minecraft.World/Zombie.cpp b/Minecraft.World/Zombie.cpp index 87e4e173..fdcd85e8 100644 --- a/Minecraft.World/Zombie.cpp +++ b/Minecraft.World/Zombie.cpp @@ -253,7 +253,7 @@ int Zombie::getHurtSound() int Zombie::getDeathSound() { return eSoundType_MOB_ZOMBIE_DEATH; -} +} int Zombie::getDeathLoot() { @@ -366,9 +366,9 @@ MobGroupData *Zombie::finalizeMobSpawn(MobGroupData *groupData, int extraData /* if (zombieData->isBaby) { setBaby(true); - + bool checkExisting = false; - if (level->random->nextFloat() < 0.05f) + if (level->random->nextFloat() < 0.05f) { vector> *entities = level->getEntitiesOfClass(typeid(Chicken), bb->grow(5.0f, 3.0f, 5.0f)); for (auto it = entities->begin(); it != entities->end(); ++it) @@ -384,7 +384,7 @@ MobGroupData *Zombie::finalizeMobSpawn(MobGroupData *groupData, int extraData /* } } - if (!checkExisting && level->random->nextFloat() < 0.05f) + if (!checkExisting && level->random->nextFloat() < 0.05f) { shared_ptr chicken = std::make_shared(level); chicken->moveTo(x, y, z, yRot, 0); @@ -532,3 +532,26 @@ Zombie::ZombieGroupData::ZombieGroupData(bool baby, bool villager) isBaby = baby; isVillager = villager; } + +int Zombie::getAttackTooltipId(std::shared_ptr player) +{ + return IDS_TOOLTIPS_HIT; +} + +int Zombie::getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem) +{ + int heldItemId = -1; + if (heldItem != nullptr && heldItem->getItem() != nullptr) + { + heldItemId = heldItem->getItem()->id; + } + + static GoldenAppleItem *goldapple = static_cast(Item::golden_apple); + + if (this->isVillager() && this->isWeakened() && (heldItemId == Item::golden_apple_Id) && !goldapple->isFoil(heldItem)) + return IDS_TOOLTIPS_CURE; + + return 0; +} diff --git a/Minecraft.World/Zombie.h b/Minecraft.World/Zombie.h index f788ea63..bf627803 100644 --- a/Minecraft.World/Zombie.h +++ b/Minecraft.World/Zombie.h @@ -94,6 +94,10 @@ protected: public: virtual bool isConverting(); + virtual int getAttackTooltipId(std::shared_ptr player); + virtual int getInteractTooltipId(Level *level, + std::shared_ptr player, + std::shared_ptr heldItem); protected: virtual void finishConversion(); diff --git a/cmake/ClientSources.cmake b/cmake/ClientSources.cmake new file mode 100644 index 00000000..5c7759a8 --- /dev/null +++ b/cmake/ClientSources.cmake @@ -0,0 +1,500 @@ +set(MINECRAFT_CLIENT_SOURCES + "../include/lce_filesystem/lce_filesystem.cpp" + + "AbstractTexturePack.cpp" + "AchievementPopup.cpp" + "AchievementScreen.cpp" + "AllowAllCuller.cpp" + "ArchiveFile.cpp" + "ArrowRenderer.cpp" + "BatModel.cpp" + "BatRenderer.cpp" + "BeaconRenderer.cpp" + "BlazeModel.cpp" + "BlazeRenderer.cpp" + "BoatModel.cpp" + "BoatRenderer.cpp" + "BookModel.cpp" + "BossMobGuiInfo.cpp" + "BreakingItemParticle.cpp" + "BubbleParticle.cpp" + "BufferedImage.cpp" + "Button.cpp" + "Camera.cpp" + "CaveSpiderRenderer.cpp" + "ChatScreen.cpp" + "ChestModel.cpp" + "ChestRenderer.cpp" + "ChickenModel.cpp" + "ChickenRenderer.cpp" + "Chunk.cpp" + "ClientConnection.cpp" + "ClientConstants.cpp" + "ClockTexture.cpp" + "Common/Audio/Consoles_SoundEngine.cpp" + "Common/Audio/SoundEngine.cpp" + "Common/Audio/SoundNames.cpp" + "Common/Colours/ColourTable.cpp" + "Common/ConsoleGameMode.cpp" + "Common/Console_Utils.cpp" + "Common/Consoles_App.cpp" + "Common/DLC/DLCAudioFile.cpp" + "Common/DLC/DLCCapeFile.cpp" + "Common/DLC/DLCColourTableFile.cpp" + "Common/DLC/DLCFile.cpp" + "Common/DLC/DLCGameRulesFile.cpp" + "Common/DLC/DLCGameRulesHeader.cpp" + "Common/DLC/DLCLocalisationFile.cpp" + "Common/DLC/DLCManager.cpp" + "Common/DLC/DLCPack.cpp" + "Common/DLC/DLCSkinFile.cpp" + "Common/DLC/DLCTextureFile.cpp" + "Common/DLC/DLCUIDataFile.cpp" + "Common/GameRules/AddEnchantmentRuleDefinition.cpp" + "Common/GameRules/AddItemRuleDefinition.cpp" + "Common/GameRules/ApplySchematicRuleDefinition.cpp" + "Common/GameRules/BiomeOverride.cpp" + "Common/GameRules/CollectItemRuleDefinition.cpp" + "Common/GameRules/CompleteAllRuleDefinition.cpp" + "Common/GameRules/CompoundGameRuleDefinition.cpp" + "Common/GameRules/ConsoleGenerateStructure.cpp" + "Common/GameRules/ConsoleSchematicFile.cpp" + "Common/GameRules/GameRule.cpp" + "Common/GameRules/GameRuleDefinition.cpp" + "Common/GameRules/GameRuleManager.cpp" + "Common/GameRules/LevelGenerationOptions.cpp" + "Common/GameRules/LevelGenerators.cpp" + "Common/GameRules/LevelRules.cpp" + "Common/GameRules/LevelRuleset.cpp" + "Common/GameRules/NamedAreaRuleDefinition.cpp" + "Common/GameRules/StartFeature.cpp" + "Common/GameRules/UpdatePlayerRuleDefinition.cpp" + "Common/GameRules/UseTileRuleDefinition.cpp" + "Common/GameRules/XboxStructureActionGenerateBox.cpp" + "Common/GameRules/XboxStructureActionPlaceBlock.cpp" + "Common/GameRules/XboxStructureActionPlaceContainer.cpp" + "Common/GameRules/XboxStructureActionPlaceSpawner.cpp" + "Common/Leaderboards/LeaderboardInterface.cpp" + "Common/Leaderboards/LeaderboardManager.cpp" + "Common/Network/GameNetworkManager.cpp" + "Common/Network/PlatformNetworkManagerStub.cpp" + "Common/Telemetry/TelemetryManager.cpp" + "Common/Trial/TrialMode.cpp" + "Common/Tutorial/AreaConstraint.cpp" + "Common/Tutorial/AreaHint.cpp" + "Common/Tutorial/AreaTask.cpp" + "Common/Tutorial/ChangeStateConstraint.cpp" + "Common/Tutorial/ChoiceTask.cpp" + "Common/Tutorial/CompleteUsingItemTask.cpp" + "Common/Tutorial/ControllerTask.cpp" + "Common/Tutorial/CraftTask.cpp" + "Common/Tutorial/DiggerItemHint.cpp" + "Common/Tutorial/EffectChangedTask.cpp" + "Common/Tutorial/FullTutorial.cpp" + "Common/Tutorial/FullTutorialActiveTask.cpp" + "Common/Tutorial/FullTutorialMode.cpp" + "Common/Tutorial/HorseChoiceTask.cpp" + "Common/Tutorial/InfoTask.cpp" + "Common/Tutorial/InputConstraint.cpp" + "Common/Tutorial/LookAtEntityHint.cpp" + "Common/Tutorial/LookAtTileHint.cpp" + "Common/Tutorial/PickupTask.cpp" + "Common/Tutorial/ProcedureCompoundTask.cpp" + "Common/Tutorial/ProgressFlagTask.cpp" + "Common/Tutorial/RideEntityTask.cpp" + "Common/Tutorial/StatTask.cpp" + "Common/Tutorial/TakeItemHint.cpp" + "Common/Tutorial/Tutorial.cpp" + "Common/Tutorial/TutorialHint.cpp" + "Common/Tutorial/TutorialMessage.cpp" + "Common/Tutorial/TutorialMode.cpp" + "Common/Tutorial/TutorialTask.cpp" + "Common/Tutorial/UseItemTask.cpp" + "Common/Tutorial/UseTileTask.cpp" + "Common/Tutorial/XuiCraftingTask.cpp" + "Common/UI/IUIScene_AbstractContainerMenu.cpp" + "Common/UI/IUIScene_AnvilMenu.cpp" + "Common/UI/IUIScene_BeaconMenu.cpp" + "Common/UI/IUIScene_BrewingMenu.cpp" + "Common/UI/IUIScene_CommandBlockMenu.cpp" + "Common/UI/IUIScene_ContainerMenu.cpp" + "Common/UI/IUIScene_CraftingMenu.cpp" + "Common/UI/IUIScene_CreativeMenu.cpp" + "Common/UI/IUIScene_DispenserMenu.cpp" + "Common/UI/IUIScene_EnchantingMenu.cpp" + "Common/UI/IUIScene_FireworksMenu.cpp" + "Common/UI/IUIScene_FurnaceMenu.cpp" + "Common/UI/IUIScene_HUD.cpp" + "Common/UI/IUIScene_HopperMenu.cpp" + "Common/UI/IUIScene_HorseInventoryMenu.cpp" + "Common/UI/IUIScene_InventoryMenu.cpp" + "Common/UI/IUIScene_PauseMenu.cpp" + "Common/UI/IUIScene_StartGame.cpp" + "Common/UI/IUIScene_TradingMenu.cpp" + "Common/UI/UIBitmapFont.cpp" + "Common/UI/UIComponent_Chat.cpp" + "Common/UI/UIComponent_DebugUIConsole.cpp" + "Common/UI/UIComponent_DebugUIMarketingGuide.cpp" + "Common/UI/UIComponent_Logo.cpp" + "Common/UI/UIComponent_MenuBackground.cpp" + "Common/UI/UIComponent_Panorama.cpp" + "Common/UI/UIComponent_PressStartToPlay.cpp" + "Common/UI/UIComponent_Tooltips.cpp" + "Common/UI/UIComponent_TutorialPopup.cpp" + "Common/UI/UIControl.cpp" + "Common/UI/UIControl_Base.cpp" + "Common/UI/UIControl_BeaconEffectButton.cpp" + "Common/UI/UIControl_BitmapIcon.cpp" + "Common/UI/UIControl_Button.cpp" + "Common/UI/UIControl_ButtonList.cpp" + "Common/UI/UIControl_CheckBox.cpp" + "Common/UI/UIControl_Cursor.cpp" + "Common/UI/UIControl_DLCList.cpp" + "Common/UI/UIControl_DynamicLabel.cpp" + "Common/UI/UIControl_EnchantmentBook.cpp" + "Common/UI/UIControl_EnchantmentButton.cpp" + "Common/UI/UIControl_HTMLLabel.cpp" + "Common/UI/UIControl_Label.cpp" + "Common/UI/UIControl_LeaderboardList.cpp" + "Common/UI/UIControl_MinecraftHorse.cpp" + "Common/UI/UIControl_MinecraftPlayer.cpp" + "Common/UI/UIControl_PlayerList.cpp" + "Common/UI/UIControl_PlayerSkinPreview.cpp" + "Common/UI/UIControl_Progress.cpp" + "Common/UI/UIControl_SaveList.cpp" + "Common/UI/UIControl_Slider.cpp" + "Common/UI/UIControl_SlotList.cpp" + "Common/UI/UIControl_SpaceIndicatorBar.cpp" + "Common/UI/UIControl_TextInput.cpp" + "Common/UI/UIControl_TexturePackList.cpp" + "Common/UI/UIController.cpp" + "Common/UI/UIFontData.cpp" + "Common/UI/UIGroup.cpp" + "Common/UI/UILayer.cpp" + "Common/UI/UIScene.cpp" + "Common/UI/UIScene_AbstractContainerMenu.cpp" + "Common/UI/UIScene_AnvilMenu.cpp" + "Common/UI/UIScene_BeaconMenu.cpp" + "Common/UI/UIScene_BrewingStandMenu.cpp" + "Common/UI/UIScene_ConnectingProgress.cpp" + "Common/UI/UIScene_ContainerMenu.cpp" + "Common/UI/UIScene_ControlsMenu.cpp" + "Common/UI/UIScene_CraftingMenu.cpp" + "Common/UI/UIScene_CreateWorldMenu.cpp" + "Common/UI/UIScene_CreativeMenu.cpp" + "Common/UI/UIScene_Credits.cpp" + "Common/UI/UIScene_DLCMainMenu.cpp" + "Common/UI/UIScene_DLCOffersMenu.cpp" + "Common/UI/UIScene_DeathMenu.cpp" + "Common/UI/UIScene_DebugCreateSchematic.cpp" + "Common/UI/UIScene_DebugOptions.cpp" + "Common/UI/UIScene_DebugOverlay.cpp" + "Common/UI/UIScene_DebugSetCamera.cpp" + "Common/UI/UIScene_DispenserMenu.cpp" + "Common/UI/UIScene_EULA.cpp" + "Common/UI/UIScene_EnchantingMenu.cpp" + "Common/UI/UIScene_EndPoem.cpp" + "Common/UI/UIScene_FireworksMenu.cpp" + "Common/UI/UIScene_FullscreenProgress.cpp" + "Common/UI/UIScene_FurnaceMenu.cpp" + "Common/UI/UIScene_HUD.cpp" + "Common/UI/UIScene_HelpAndOptionsMenu.cpp" + "Common/UI/UIScene_HopperMenu.cpp" + "Common/UI/UIScene_HorseInventoryMenu.cpp" + "Common/UI/UIScene_HowToPlay.cpp" + "Common/UI/UIScene_HowToPlayMenu.cpp" + "Common/UI/UIScene_InGameHostOptionsMenu.cpp" + "Common/UI/UIScene_InGameInfoMenu.cpp" + "Common/UI/UIScene_InGamePlayerOptionsMenu.cpp" + "Common/UI/UIScene_Intro.cpp" + "Common/UI/UIScene_InventoryMenu.cpp" + "Common/UI/UIScene_JoinMenu.cpp" + "Common/UI/UIScene_Keyboard.cpp" + "Common/UI/UIScene_LanguageSelector.cpp" + "Common/UI/UIScene_LaunchMoreOptionsMenu.cpp" + "Common/UI/UIScene_LeaderboardsMenu.cpp" + "Common/UI/UIScene_LoadMenu.cpp" + "Common/UI/UIScene_LoadOrJoinMenu.cpp" + "Common/UI/UIScene_MainMenu.cpp" + "Common/UI/UIScene_MessageBox.cpp" + "Common/UI/UIScene_NewUpdateMessage.cpp" + "Common/UI/UIScene_PauseMenu.cpp" + "Common/UI/UIScene_QuadrantSignin.cpp" + "Common/UI/UIScene_ReinstallMenu.cpp" + "Common/UI/UIScene_SaveMessage.cpp" + "Common/UI/UIScene_SettingsAudioMenu.cpp" + "Common/UI/UIScene_SettingsControlMenu.cpp" + "Common/UI/UIScene_SettingsGraphicsMenu.cpp" + "Common/UI/UIScene_SettingsMenu.cpp" + "Common/UI/UIScene_SettingsOptionsMenu.cpp" + "Common/UI/UIScene_SettingsUIMenu.cpp" + "Common/UI/UIScene_SignEntryMenu.cpp" + "Common/UI/UIScene_SkinSelectMenu.cpp" + "Common/UI/UIScene_TeleportMenu.cpp" + "Common/UI/UIScene_Timer.cpp" + "Common/UI/UIScene_TradingMenu.cpp" + "Common/UI/UIScene_TrialExitUpsell.cpp" + "Common/UI/UIString.cpp" + "Common/UI/UITTFFont.cpp" + "Common/zlib/adler32.c" + "Common/zlib/compress.c" + "Common/zlib/crc32.c" + "Common/zlib/deflate.c" + "Common/zlib/gzclose.c" + "Common/zlib/gzlib.c" + "Common/zlib/gzread.c" + "Common/zlib/gzwrite.c" + "Common/zlib/infback.c" + "Common/zlib/inffast.c" + "Common/zlib/inflate.c" + "Common/zlib/inftrees.c" + "Common/zlib/trees.c" + "Common/zlib/uncompr.c" + "Common/zlib/zutil.c" + "CompassTexture.cpp" + "ConfirmScreen.cpp" + "ConsoleInput.cpp" + "ControlsScreen.cpp" + "CowModel.cpp" + "CowRenderer.cpp" + "CreateWorldScreen.cpp" + "CreeperModel.cpp" + "CreeperRenderer.cpp" + "CritParticle.cpp" + "CritParticle2.cpp" + "Cube.cpp" + "DLCTexturePack.cpp" + "DeathScreen.cpp" + "DefaultRenderer.cpp" + "DefaultTexturePack.cpp" + "DemoUser.cpp" + "DerivedServerLevel.cpp" + "DirtyChunkSorter.cpp" + "DispenserBootstrap.cpp" + "DistanceChunkSorter.cpp" + "DragonBreathParticle.cpp" + "DragonModel.cpp" + "DripParticle.cpp" + "EchantmentTableParticle.cpp" + "EditBox.cpp" + "EnchantTableRenderer.cpp" + "EnderChestRenderer.cpp" + "EnderCrystalModel.cpp" + "EnderCrystalRenderer.cpp" + "EnderDragonRenderer.cpp" + "EnderParticle.cpp" + "EndermanModel.cpp" + "EndermanRenderer.cpp" + "EntityRenderDispatcher.cpp" + "EntityRenderer.cpp" + "EntityTileRenderer.cpp" + "EntityTracker.cpp" + "ErrorScreen.cpp" + "ExperienceOrbRenderer.cpp" + "ExplodeParticle.cpp" + "Extrax64Stubs.cpp" + "FallingTileRenderer.cpp" + "FileTexturePack.cpp" + "FireballRenderer.cpp" + "FireworksParticles.cpp" + "FishingHookRenderer.cpp" + "FlameParticle.cpp" + "FolderTexturePack.cpp" + "Font.cpp" + "FootstepParticle.cpp" + "Frustum.cpp" + "FrustumCuller.cpp" + "FrustumData.cpp" + "GameRenderer.cpp" + "GhastModel.cpp" + "GhastRenderer.cpp" + "GiantMobRenderer.cpp" + "Gui.cpp" + "GuiComponent.cpp" + "GuiMessage.cpp" + "GuiParticle.cpp" + "GuiParticles.cpp" + "HeartParticle.cpp" + "HorseRenderer.cpp" + "HttpTexture.cpp" + "HugeExplosionParticle.cpp" + "HugeExplosionSeedParticle.cpp" + "HumanoidMobRenderer.cpp" + "HumanoidModel.cpp" + "InBedChatScreen.cpp" + "Input.cpp" + "iob_shim.asm" + "ItemFrameRenderer.cpp" + "ItemInHandRenderer.cpp" + "ItemRenderer.cpp" + "ItemSpriteRenderer.cpp" + "JoinMultiplayerScreen.cpp" + "KeyMapping.cpp" + "LargeChestModel.cpp" + "LavaParticle.cpp" + "LavaSlimeModel.cpp" + "LavaSlimeRenderer.cpp" + "LeashKnotModel.cpp" + "LeashKnotRenderer.cpp" + "LevelRenderer.cpp" + "Lighting.cpp" + "LightningBoltRenderer.cpp" + "LivingEntityRenderer.cpp" + "LocalPlayer.cpp" + "MemTexture.cpp" + "MemoryTracker.cpp" + "MinecartModel.cpp" + "MinecartRenderer.cpp" + "MinecartSpawnerRenderer.cpp" + "Minecraft.cpp" + "MinecraftServer.cpp" + "Minimap.cpp" + "MobRenderer.cpp" + "MobSkinMemTextureProcessor.cpp" + "MobSkinTextureProcessor.cpp" + "MobSpawnerRenderer.cpp" + "Model.cpp" + "ModelHorse.cpp" + "ModelPart.cpp" + "MultiPlayerChunkCache.cpp" + "MultiPlayerGameMode.cpp" + "MultiPlayerLevel.cpp" + "MultiPlayerLocalPlayer.cpp" + "MushroomCowRenderer.cpp" + "NameEntryScreen.cpp" + "NetherPortalParticle.cpp" + "NoteParticle.cpp" + "OcelotModel.cpp" + "OcelotRenderer.cpp" + "OffsettedRenderList.cpp" + "Options.cpp" + "OptionsScreen.cpp" + "PS3/PS3Extras/ShutdownManager.cpp" + "PaintingRenderer.cpp" + "Particle.cpp" + "ParticleEngine.cpp" + "PauseScreen.cpp" + "PendingConnection.cpp" + "PigModel.cpp" + "PigRenderer.cpp" + "PistonPieceRenderer.cpp" + "PlayerChunkMap.cpp" + "PlayerCloudParticle.cpp" + "PlayerConnection.cpp" + "PlayerList.cpp" + "PlayerRenderer.cpp" + "Polygon.cpp" + "PreStitchedTextureMap.cpp" + "ProgressRenderer.cpp" + "QuadrupedModel.cpp" + "Rect2i.cpp" + "RedDustParticle.cpp" + "RemotePlayer.cpp" + "RenameWorldScreen.cpp" + "Screen.cpp" + "ScreenSizeCalculator.cpp" + "ScrolledSelectionList.cpp" + "SelectWorldScreen.cpp" + "ServerChunkCache.cpp" + "ServerCommandDispatcher.cpp" + "ServerConnection.cpp" + "ServerLevel.cpp" + "ServerLevelListener.cpp" + "ServerPlayer.cpp" + "ServerPlayerGameMode.cpp" + "ServerScoreboard.cpp" + "Settings.cpp" + "SheepFurModel.cpp" + "SheepModel.cpp" + "SheepRenderer.cpp" + "SignModel.cpp" + "SignRenderer.cpp" + "SilverfishModel.cpp" + "SilverfishRenderer.cpp" + "SimpleIcon.cpp" + "SkeletonHeadModel.cpp" + "SkeletonModel.cpp" + "SkeletonRenderer.cpp" + "SkiModel.cpp" + "SkullTileRenderer.cpp" + "SlideButton.cpp" + "SlimeModel.cpp" + "SlimeRenderer.cpp" + "SmallButton.cpp" + "SmokeParticle.cpp" + "SnowManModel.cpp" + "SnowManRenderer.cpp" + "SnowShovelParticle.cpp" + "SpellParticle.cpp" + "SpiderModel.cpp" + "SpiderRenderer.cpp" + "SplashParticle.cpp" + "SquidModel.cpp" + "SquidRenderer.cpp" + "StatsCounter.cpp" + "StatsScreen.cpp" + "StatsSyncher.cpp" + "StitchSlot.cpp" + "StitchedTexture.cpp" + "Stitcher.cpp" + "StringTable.cpp" + "SuspendedParticle.cpp" + "SuspendedTownParticle.cpp" + "TakeAnimationParticle.cpp" + "TeleportCommand.cpp" + "TerrainParticle.cpp" + "Tesselator.cpp" + "TexOffs.cpp" + "Texture.cpp" + "TextureAtlas.cpp" + "TextureHolder.cpp" + "TextureManager.cpp" + "TextureMap.cpp" + "TexturePack.cpp" + "TexturePackRepository.cpp" + "Textures.cpp" + "TheEndPortalRenderer.cpp" + "TileEntityRenderDispatcher.cpp" + "TileEntityRenderer.cpp" + "TileRenderer.cpp" + "Timer.cpp" + "TitleScreen.cpp" + "TntMinecartRenderer.cpp" + "TntRenderer.cpp" + "TrackedEntity.cpp" + "User.cpp" + "Vertex.cpp" + "VideoSettingsScreen.cpp" + "ViewportCuller.cpp" + "VillagerGolemModel.cpp" + "VillagerGolemRenderer.cpp" + "VillagerModel.cpp" + "VillagerRenderer.cpp" + "VillagerZombieModel.cpp" + "WaterDropParticle.cpp" + "Windows64/Iggy/gdraw/gdraw_d3d11.cpp" + "Windows64/KeyboardMouseInput.cpp" + "Windows64/PostProcesser.cpp" + "Windows64/Leaderboards/WindowsLeaderboardManager.cpp" + "Windows64/Windows64_App.cpp" + "Windows64/Windows64_Minecraft.cpp" + "Windows64/Windows64_UIController.cpp" + "Windows64/Network/WinsockNetLayer.cpp" + "WitchModel.cpp" + "WitchRenderer.cpp" + "WitherBossModel.cpp" + "WitherBossRenderer.cpp" + "WitherSkullRenderer.cpp" + "WolfModel.cpp" + "WolfRenderer.cpp" + "WstringLookup.cpp" + "Xbox/Network/NetworkPlayerXbox.cpp" + "ZombieModel.cpp" + "ZombieRenderer.cpp" + "TooltipManager.cpp" + "compat_shims.cpp" + "glWrapper.cpp" + "stdafx.cpp" + "stubs.cpp" + "TooltipManager.cpp" +)