diff options
author | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-07-18 21:10:51 +0200 |
---|---|---|
committer | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-07-18 21:10:51 +0200 |
commit | 37140ae57835680d2c4fb3aa365082622d3a150e (patch) | |
tree | 89a636c74375b3c9f0fe77b20ecbadc693bd0989 /src/Items | |
parent | Merge branch 'master' of https://github.com/mc-server/MCServer into portals (diff) | |
parent | Monster fixes (diff) | |
download | cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.gz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.bz2 cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.lz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.xz cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.tar.zst cuberite-37140ae57835680d2c4fb3aa365082622d3a150e.zip |
Diffstat (limited to 'src/Items')
29 files changed, 426 insertions, 138 deletions
diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index f23d69731..94a14cf16 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -26,7 +26,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 821e2ab26..e7a77dcbc 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -46,20 +46,17 @@ public: { // Actual shot - produce the arrow with speed based on the ticks that the bow was charged ASSERT(a_Player != NULL); - + int BowCharge = a_Player->FinishChargingBow(); - double Force = (double)BowCharge / 20; - Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client + double Force = (double)BowCharge / 20.0; + Force = (Force * Force + 2.0 * Force) / 3.0; // This formula is used by the 1.6.2 client if (Force < 0.1) { // Too little force, ignore the shot return; } - if (Force > 1) - { - Force = 1; - } - + Force = std::min(Force, 1.0); + // Create the arrow entity: cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); if (Arrow == NULL) @@ -72,9 +69,8 @@ public: Arrow = NULL; return; } - a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow); - a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)Force); + a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); if (!a_Player->IsGameModeCreative()) { a_Player->UseEquippedItem(); diff --git a/src/Items/ItemBrewingStand.h b/src/Items/ItemBrewingStand.h index d5eefb855..7be57763c 100644 --- a/src/Items/ItemBrewingStand.h +++ b/src/Items/ItemBrewingStand.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index 68c89dd85..6d7926fa4 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -41,7 +41,7 @@ public: bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) { - if (a_BlockFace > 0) + if (a_BlockFace != BLOCK_FACE_NONE) { return false; } @@ -49,7 +49,7 @@ public: Vector3i BlockPos; if (!GetBlockFromTrace(a_World, a_Player, BlockPos)) { - return false; // Nothing in range. + return false; // Nothing in range. } if (a_World->GetBlockMeta(BlockPos.x, BlockPos.y, BlockPos.z) != 0) @@ -94,30 +94,16 @@ public: bool PlaceFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock) - { - if (a_BlockFace < 0) + { + if (a_BlockFace != BLOCK_FACE_NONE) { return false; } - BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock); - if (!CanWashAway) + BLOCKTYPE CurrentBlock; + Vector3i BlockPos; + if (!GetPlacementCoordsFromTrace(a_World, a_Player, BlockPos, CurrentBlock)) { - // The block pointed at cannot be washed away, so put fluid on top of it / on its sides - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - } - if ( - !CanWashAway && - (CurrentBlock != E_BLOCK_AIR) && - (CurrentBlock != E_BLOCK_WATER) && - (CurrentBlock != E_BLOCK_STATIONARY_WATER) && - (CurrentBlock != E_BLOCK_LAVA) && - (CurrentBlock != E_BLOCK_STATIONARY_LAVA) - ) - { - // Cannot place water here return false; } @@ -138,7 +124,7 @@ public: } // Wash away anything that was there prior to placing: - if (CanWashAway) + if (cFluidSimulator::CanWashAway(CurrentBlock)) { cBlockHandler * Handler = BlockHandler(CurrentBlock); if (Handler->DoesDropOnUnsuitable()) @@ -149,13 +135,13 @@ public: } } - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FluidBlock, 0); + a_World->SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0); return true; } - bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & BlockPos) + bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) { class cCallbacks : public cBlockTracer::cCallbacks @@ -174,7 +160,7 @@ public: { if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType)) { - if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source + if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source { return false; } @@ -198,8 +184,49 @@ public: } - BlockPos.Set(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z); + a_BlockPos = Callbacks.m_Pos; return true; } + + + bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType) + { + class cCallbacks : + public cBlockTracer::cCallbacks + { + public: + Vector3i m_Pos; + BLOCKTYPE m_ReplacedBlock; + + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + { + if (a_BlockType != E_BLOCK_AIR) + { + m_ReplacedBlock = a_BlockType; + if (!cFluidSimulator::CanWashAway(a_BlockType) && !IsBlockLiquid(a_BlockType)) + { + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace); // Was an unwashawayable block, can't overwrite it! + } + m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); // (Block could be washed away, replace it) + return true; // Abort tracing + } + return false; + } + } Callbacks; + cLineBlockTracer Tracer(*a_World, Callbacks); + Vector3d Start(a_Player->GetEyePosition()); + Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); + + // cTracer::Trace returns true when whole line was traversed. By returning true when we hit something, we ensure that this never happens if liquid could be placed + // Use this to judge whether the position is valid + if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z)) + { + a_BlockPos = Callbacks.m_Pos; + a_BlockType = Callbacks.m_ReplacedBlock; + return true; + } + + return false; + } }; diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h index 48e23ed59..d1cb091b6 100644 --- a/src/Items/ItemCake.h +++ b/src/Items/ItemCake.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemCauldron.h b/src/Items/ItemCauldron.h index 07ae12660..9617c30ef 100644 --- a/src/Items/ItemCauldron.h +++ b/src/Items/ItemCauldron.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index 60d9c3648..fc843c186 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -24,7 +24,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index f3677c28c..c1b439024 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override @@ -33,8 +33,8 @@ public: a_BlockType = (m_ItemType == E_ITEM_WOODEN_DOOR) ? E_BLOCK_WOODEN_DOOR : E_BLOCK_IRON_DOOR; cChunkInterface ChunkInterface(a_World->GetChunkMap()); bool Meta = BlockHandler(a_BlockType)->GetPlacementBlockTypeMeta( - ChunkInterface, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, + ChunkInterface, a_Player, + a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta ); diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 3b1ad1717..6350a38ba 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -17,13 +17,15 @@ -///////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// // cFloaterCallback class cFloaterCallback : public cEntityCallback { public: - cFloaterCallback(void) : + cFloaterCallback(void) : m_CanPickup(false), m_AttachedMobID(-1) { @@ -49,14 +51,19 @@ protected: Vector3d m_Pos; } ; -//////////////////////////////////////////////////////////////////////////// -// cSweepEntityCallback + + + + +//////////////////////////////////////////////////////////////////////////////// +// cSweepEntityCallback: + class cSweepEntityCallback : public cEntityCallback { public: cSweepEntityCallback(Vector3d a_PlayerPos) : - m_PlayerPos(a_PlayerPos) + m_PlayerPos(a_PlayerPos) { } @@ -73,6 +80,8 @@ protected: + + class cItemFishingRodHandler : public cItemHandler { @@ -106,19 +115,19 @@ public: { cItems Drops; int ItemCategory = a_World->GetTickRandomNumber(99); - if (ItemCategory <= 4) // Treasures 5% + if (ItemCategory <= 4) // Treasures 5% { int Treasure = a_World->GetTickRandomNumber(5); switch (Treasure) { case 0: { - Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments + Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments break; } case 1: { - Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book + Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book break; } case 2: @@ -201,7 +210,7 @@ public: if (FishType <= 1) // Clownfish has a 2% chance of spawning { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); - } + } else if (FishType <= 12) // Pufferfish has a 13% chance of spawning { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); @@ -237,3 +246,7 @@ public: return true; } } ; + + + + diff --git a/src/Items/ItemFlowerPot.h b/src/Items/ItemFlowerPot.h index 60bf87985..320dce997 100644 --- a/src/Items/ItemFlowerPot.h +++ b/src/Items/ItemFlowerPot.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index f639423ae..178bc2fca 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -19,6 +19,7 @@ #include "ItemCloth.h" #include "ItemComparator.h" #include "ItemDoor.h" +#include "ItemMilk.h" #include "ItemDye.h" #include "ItemEmptyMap.h" #include "ItemFishingRod.h" @@ -34,6 +35,7 @@ #include "ItemNetherWart.h" #include "ItemPainting.h" #include "ItemPickaxe.h" +#include "ItemPotion.h" #include "ItemThrowable.h" #include "ItemRedstoneDust.h" #include "ItemRedstoneRepeater.h" @@ -44,6 +46,7 @@ #include "ItemSign.h" #include "ItemMobHead.h" #include "ItemSpawnEgg.h" +#include "ItemString.h" #include "ItemSugarcane.h" #include "ItemSword.h" @@ -62,7 +65,7 @@ cItemHandler * cItemHandler::m_ItemHandler[2268]; cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) { - if (a_ItemType < 0) + if ((a_ItemType < 0) || ((unsigned long)a_ItemType >= ARRAYCOUNT(m_ItemHandler))) { // Either nothing (-1), or bad value, both cases should return the air handler if (a_ItemType < -1) @@ -119,9 +122,11 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); case E_ITEM_MAP: return new cItemMapHandler(); + case E_ITEM_MILK: return new cItemMilkHandler(); case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType); + case E_ITEM_POTIONS: return new cItemPotionHandler(); case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType); case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType); @@ -129,6 +134,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType); case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); + case E_ITEM_STRING: return new cItemStringHandler(a_ItemType); case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType); case E_ITEM_WOODEN_HOE: @@ -356,7 +362,7 @@ char cItemHandler::GetMaxStackSize(void) return 64; } - switch (m_ItemType) //sorted by id + switch (m_ItemType) { case E_ITEM_ARROW: return 64; case E_ITEM_BAKED_POTATO: return 64; @@ -452,14 +458,14 @@ char cItemHandler::GetMaxStackSize(void) bool cItemHandler::IsTool() { // TODO: Rewrite this to list all tools specifically - return - (m_ItemType >= 256 && m_ItemType <= 259) - || (m_ItemType == 261) - || (m_ItemType >= 267 && m_ItemType <= 279) - || (m_ItemType >= 283 && m_ItemType <= 286) - || (m_ItemType >= 290 && m_ItemType <= 294) - || (m_ItemType == 325) - || (m_ItemType == 346); + return + ((m_ItemType >= 256) && (m_ItemType <= 259)) || + (m_ItemType == 261) || + ((m_ItemType >= 267) && (m_ItemType <= 279)) || + ((m_ItemType >= 283) && (m_ItemType <= 286)) || + ((m_ItemType >= 290) && (m_ItemType <= 294)) || + (m_ItemType == 325) || + (m_ItemType == 346); } @@ -468,33 +474,17 @@ bool cItemHandler::IsTool() bool cItemHandler::IsFood(void) { - switch (m_ItemType) - { - case E_ITEM_RED_APPLE: - case E_ITEM_GOLDEN_APPLE: - case E_ITEM_MUSHROOM_SOUP: - case E_ITEM_BREAD: - case E_ITEM_RAW_PORKCHOP: - case E_ITEM_COOKED_PORKCHOP: - case E_ITEM_MILK: - case E_ITEM_RAW_FISH: - case E_ITEM_COOKED_FISH: - case E_ITEM_COOKIE: - case E_ITEM_MELON_SLICE: - case E_ITEM_RAW_BEEF: - case E_ITEM_STEAK: - case E_ITEM_RAW_CHICKEN: - case E_ITEM_COOKED_CHICKEN: - case E_ITEM_ROTTEN_FLESH: - case E_ITEM_SPIDER_EYE: - case E_ITEM_CARROT: - case E_ITEM_POTATO: - case E_ITEM_BAKED_POTATO: - case E_ITEM_POISONOUS_POTATO: - { - return true; - } - } // switch (m_ItemType) + return false; +} + + + + + +bool cItemHandler::IsDrinkable(short a_ItemDamage) +{ + UNUSED(a_ItemDamage); + return false; } @@ -535,7 +525,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) bool cItemHandler::GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) @@ -552,7 +542,7 @@ bool cItemHandler::GetPlacementBlockTypeMeta( cChunkInterface ChunkInterface(a_World->GetChunkMap()); return BlockH->GetPlacementBlockTypeMeta( ChunkInterface, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, + a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta ); @@ -578,7 +568,7 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) cFastRandom r1; if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0) { - a_Player->FoodPoison(300); + a_Player->FoodPoison(600); // Give the player food poisoning for 30 seconds. } } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index e13198cd7..c7362c5f4 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -28,7 +28,7 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir); /** Called when the client sends the SHOOT status in the lclk packet */ - virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) + virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { UNUSED(a_BlockX); UNUSED(a_BlockY); @@ -60,7 +60,7 @@ public: { double Saturation; int FoodLevel; - int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning + int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) : Saturation(a_Saturation), @@ -82,24 +82,27 @@ public: /** Indicates if this item is food */ virtual bool IsFood(void); + /** Indicates if this item is drinkable */ + virtual bool IsDrinkable(short a_ItemDamage); + /** Blocks simply get placed */ virtual bool IsPlaceable(void); /** Can the anvil repair this item, when a_Item is the second input? */ virtual bool CanRepairWithRawMaterial(short a_ItemType); - /** Called before a block is placed into a world. + /** Called before a block is placed into a world. The handler should return true to allow placement, false to refuse. Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. */ virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ); - /** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can�t) DEFAULT: False */ + /** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can't) DEFAULT: False */ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType); static cItemHandler * GetItemHandler(int a_ItemType); @@ -109,11 +112,11 @@ public: protected: int m_ItemType; - static cItemHandler *CreateItemHandler(int m_ItemType); + static cItemHandler * CreateItemHandler(int m_ItemType); static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1]; - static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized + static bool m_HandlerInitialized; // used to detect if the itemhandlers are initialized }; -//Short function +// Short function inline cItemHandler *ItemHandler(int a_ItemType) { return cItemHandler::GetItemHandler(a_ItemType); } diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index b258b4aea..87e20ecf0 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -27,9 +27,9 @@ public: return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again if (Block == E_BLOCK_AIR) { diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h index 12cb45d1c..f48126dc5 100644 --- a/src/Items/ItemLeaves.h +++ b/src/Items/ItemLeaves.h @@ -20,7 +20,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override @@ -31,7 +31,7 @@ public: a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta ); - a_BlockMeta = a_BlockMeta | 0x4; //0x4 bit set means this is a player-placed leaves block, not to be decayed + a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed return res; } } ; diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h index 32f49cab6..9f98bf85f 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -52,8 +52,8 @@ public: case E_BLOCK_TNT: { // Activate the TNT: - a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f); - a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0); + a_World->BroadcastSoundEffect("game.tnt.primed", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 1.0f); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom break; } @@ -68,7 +68,7 @@ public: if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) { a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0); - a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F); + a_World->BroadcastSoundEffect("fire.ignite", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0F, 1.04F); break; } } diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h index bc650cdbd..b9d837384 100644 --- a/src/Items/ItemLilypad.h +++ b/src/Items/ItemLilypad.h @@ -25,7 +25,7 @@ public: virtual bool IsPlaceable(void) override { - return false; // Set as not placeable so OnItemUse is called + return false; // Set as not placeable so OnItemUse is called } @@ -57,7 +57,7 @@ public: { if (IsBlockWater(a_CBBlockType)) { - if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged + if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged { return false; } diff --git a/src/Items/ItemMilk.h b/src/Items/ItemMilk.h new file mode 100644 index 000000000..db7bc13be --- /dev/null +++ b/src/Items/ItemMilk.h @@ -0,0 +1,28 @@ + +#pragma once + +class cItemMilkHandler: + public cItemHandler +{ + typedef cItemHandler super; +public: + cItemMilkHandler(): + super(E_ITEM_MILK) + { + } + + virtual bool IsDrinkable(short a_ItemDamage) override + { + UNUSED(a_ItemDamage); + return true; + } + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override + { + UNUSED(a_Item); + a_Player->ClearEntityEffects(); + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_BUCKET); + return true; + } +}; diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index 5ae040282..4c36fe8d8 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -26,7 +26,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemNetherWart.h b/src/Items/ItemNetherWart.h index a6a9a286a..10a0864b5 100644 --- a/src/Items/ItemNetherWart.h +++ b/src/Items/ItemNetherWart.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index e4bb76ebe..a2a77ce21 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -27,9 +27,9 @@ public: return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again if (Block == E_BLOCK_AIR) { @@ -38,14 +38,14 @@ public: // The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces switch (a_Dir) { - case BLOCK_FACE_ZP: break; // Initialised to zero + case BLOCK_FACE_ZP: break; // Initialised to zero case BLOCK_FACE_ZM: Dir = 2; break; case BLOCK_FACE_XM: Dir = 1; break; case BLOCK_FACE_XP: Dir = 3; break; default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false; } - static const struct // Define all the possible painting titles + static const struct // Define all the possible painting titles { AString Title; } gPaintingTitlesList[] = diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h new file mode 100644 index 000000000..f3afbf99b --- /dev/null +++ b/src/Items/ItemPotion.h @@ -0,0 +1,199 @@ + +#pragma once + +#include "../Entities/EntityEffect.h" +#include "../Entities/SplashPotionEntity.h" + +class cItemPotionHandler: + public cItemHandler +{ + typedef cItemHandler super; + +public: + + cItemPotionHandler(): + super(E_ITEM_POTION) + { + } + + + /** Returns the potion particle type (used by the client for visuals), based on the potion's damage value */ + static int GetPotionParticleType(short a_ItemDamage) + { + // Lowest six bits + return (a_ItemDamage & 0x3f); + } + + + /** Translates the potion's damage value into the entity effect that the potion gives */ + static cEntityEffect::eType GetEntityEffectType(short a_ItemDamage) + { + // Lowest four bits + // Potion effect bits are different from entity effect values + // For reference: http://minecraft.gamepedia.com/Data_values#.22Potion_effect.22_bits + switch (a_ItemDamage & 0x0f) + { + case 0x01: return cEntityEffect::effRegeneration; + case 0x02: return cEntityEffect::effSpeed; + case 0x03: return cEntityEffect::effFireResistance; + case 0x04: return cEntityEffect::effPoison; + case 0x05: return cEntityEffect::effInstantHealth; + case 0x06: return cEntityEffect::effNightVision; + case 0x08: return cEntityEffect::effWeakness; + case 0x09: return cEntityEffect::effStrength; + case 0x0a: return cEntityEffect::effSlowness; + case 0x0c: return cEntityEffect::effInstantDamage; + case 0x0d: return cEntityEffect::effWaterBreathing; + case 0x0e: return cEntityEffect::effInvisibility; + + // No effect potions + case 0x00: + case 0x07: + case 0x0b: // Will be potion of leaping in 1.8 + case 0x0f: + { + break; + } + } + return cEntityEffect::effNoEffect; + } + + + /** Retrieves the intensity level from the potion's damage value. + Returns 0 for level I potions, 1 for level II potions. */ + static short GetEntityEffectIntensity(short a_ItemDamage) + { + // Level II potion if the fifth lowest bit is set + return ((a_ItemDamage & 0x20) != 0) ? 1 : 0; + } + + + /** Returns the effect duration, in ticks, based on the potion's damage value */ + static int GetEntityEffectDuration(short a_ItemDamage) + { + // Base duration in ticks + int base = 0; + double TierCoeff = 1, ExtCoeff = 1, SplashCoeff = 1; + + switch (GetEntityEffectType(a_ItemDamage)) + { + case cEntityEffect::effRegeneration: + case cEntityEffect::effPoison: + { + base = 900; + break; + } + + case cEntityEffect::effSpeed: + case cEntityEffect::effFireResistance: + case cEntityEffect::effNightVision: + case cEntityEffect::effStrength: + case cEntityEffect::effWaterBreathing: + case cEntityEffect::effInvisibility: + { + base = 3600; + break; + } + + case cEntityEffect::effWeakness: + case cEntityEffect::effSlowness: + { + base = 1800; + break; + } + } + + // If potion is level II, half the duration. If not, stays the same + TierCoeff = (GetEntityEffectIntensity(a_ItemDamage) > 0) ? 0.5 : 1; + + // If potion is extended, multiply duration by 8/3. If not, stays the same + // Extended potion if sixth lowest bit is set + ExtCoeff = (a_ItemDamage & 0x40) ? (8.0 / 3.0) : 1; + + // If potion is splash potion, multiply duration by 3/4. If not, stays the same + SplashCoeff = IsPotionDrinkable(a_ItemDamage) ? 1 : 0.75; + + // Ref.: + // http://minecraft.gamepedia.com/Data_values#.22Tier.22_bit + // http://minecraft.gamepedia.com/Data_values#.22Extended_duration.22_bit + // http://minecraft.gamepedia.com/Data_values#.22Splash_potion.22_bit + + return (int)(base * TierCoeff * ExtCoeff * SplashCoeff); + } + + + /** Returns true if the potion with the given damage is drinkable */ + static bool IsPotionDrinkable(short a_ItemDamage) + { + // Drinkable potion if 13th lowest bit is set + // Ref.: http://minecraft.gamepedia.com/Potions#Data_value_table + return ((a_ItemDamage & 0x2000) != 0); + } + + + // cItemHandler overrides: + virtual bool IsDrinkable(short a_ItemDamage) override + { + // Drinkable potion if 13th lowest bit is set + // Ref.: http://minecraft.gamepedia.com/Potions#Data_value_table + return IsPotionDrinkable(a_ItemDamage); + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + { + short PotionDamage = a_Item.m_ItemDamage; + + // Do not throw non-splash potions: + if (IsPotionDrinkable(PotionDamage)) + { + return false; + } + + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * 7; + + cSplashPotionEntity * Projectile = new cSplashPotionEntity( + a_Player, Pos.x, Pos.y, Pos.z, Speed, + GetEntityEffectType(PotionDamage), cEntityEffect(GetEntityEffectDuration(PotionDamage), + GetEntityEffectIntensity(PotionDamage)), GetPotionParticleType(PotionDamage) + ); + if (Projectile == NULL) + { + return false; + } + if (!Projectile->Initialize(*a_World)) + { + delete Projectile; + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + return true; + } + + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override + { + short PotionDamage = a_Item->m_ItemDamage; + + // Do not drink undrinkable potions: + if (!IsDrinkable(a_Item->m_ItemDamage)) + { + return false; + } + + a_Player->AddEntityEffect(GetEntityEffectType(PotionDamage), GetEntityEffectDuration(PotionDamage), GetEntityEffectIntensity(PotionDamage)); + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE); + return true; + } +}; + + + + diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h index 274d905a5..a2289239c 100644 --- a/src/Items/ItemRedstoneDust.h +++ b/src/Items/ItemRedstoneDust.h @@ -22,12 +22,12 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust + if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust { return false; } diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index c5fb5d566..13a797d00 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -24,7 +24,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h index 61b1a32be..dbcb12be5 100644 --- a/src/Items/ItemSapling.h +++ b/src/Items/ItemSapling.h @@ -20,7 +20,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 7283edcee..54a1183d7 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -25,12 +25,12 @@ public: virtual bool IsFood(void) override { - switch (m_ItemType) // Special cases, both a seed and food + switch (m_ItemType) // Special cases, both a seed and food { case E_ITEM_CARROT: case E_ITEM_POTATO: return true; default: return false; - } + } } virtual FoodInfo GetFoodInfo(void) override @@ -40,12 +40,12 @@ public: case E_ITEM_CARROT: return FoodInfo(4, 4.8); case E_ITEM_POTATO: return FoodInfo(1, 0.6); default: return FoodInfo(0, 0); - } + } } virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 60cf0f5f8..235a4fa93 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -27,7 +27,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemString.h b/src/Items/ItemString.h new file mode 100644 index 000000000..a97fbe0ce --- /dev/null +++ b/src/Items/ItemString.h @@ -0,0 +1,39 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemStringHandler : + public cItemHandler +{ +public: + cItemStringHandler(int a_ItemType) : + cItemHandler(a_ItemType) + { + } + + virtual bool IsPlaceable(void) override + { + return true; + } + + virtual bool GetPlacementBlockTypeMeta( + cWorld * a_World, cPlayer * a_Player, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_CursorX, int a_CursorY, int a_CursorZ, + BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta + ) override + { + a_BlockType = E_BLOCK_TRIPWIRE; + a_BlockMeta = 0; + return true; + } +}; + + + + diff --git a/src/Items/ItemSugarcane.h b/src/Items/ItemSugarcane.h index e891cc367..dd2e2ece3 100644 --- a/src/Items/ItemSugarcane.h +++ b/src/Items/ItemSugarcane.h @@ -23,7 +23,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index 25935a1bc..c151c5d3a 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -33,16 +33,9 @@ public: // Play sound cFastRandom Random; - a_World->BroadcastSoundEffect( - "random.bow", - (int)std::floor(a_Player->GetPosX() * 8.0), - (int)std::floor((a_Player->GetPosY() - a_Player->GetHeight()) * 8.0), - (int)std::floor(a_Player->GetPosZ() * 8.0), - 0.5F, - 0.4F / (Random.NextFloat(1.0F) * 0.4F + 0.8F) - ); - - if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0) + a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f)); + + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0) { return false; } @@ -142,7 +135,7 @@ public: return false; } - if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0) + if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0) { return false; } |