diff options
Diffstat (limited to 'source')
38 files changed, 708 insertions, 171 deletions
diff --git a/source/Bindings.cpp b/source/Bindings.cpp index bc96bd098..5e1fc4c8e 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/09/13 19:50:08. +** Generated automatically by tolua++-1.0.92 on 11/10/13 18:40:47. */ #ifndef __cplusplus @@ -15845,6 +15845,38 @@ static int tolua_AllToLua_cItem_IsFullStack00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetMaxStackSize of class cItem */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cItem_GetMaxStackSize00 +static int tolua_AllToLua_cItem_GetMaxStackSize00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cItem",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cItem* self = (const cItem*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMaxStackSize'", NULL); +#endif + { + char tolua_ret = (char) self->GetMaxStackSize(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetMaxStackSize'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* get function: m_ItemType of class cItem */ #ifndef TOLUA_DISABLE_tolua_get_cItem_m_ItemType static int tolua_get_cItem_m_ItemType(lua_State* tolua_S) @@ -30521,6 +30553,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsDamageable",tolua_AllToLua_cItem_IsDamageable00); tolua_function(tolua_S,"IsStackableWith",tolua_AllToLua_cItem_IsStackableWith00); tolua_function(tolua_S,"IsFullStack",tolua_AllToLua_cItem_IsFullStack00); + tolua_function(tolua_S,"GetMaxStackSize",tolua_AllToLua_cItem_GetMaxStackSize00); tolua_variable(tolua_S,"m_ItemType",tolua_get_cItem_m_ItemType,tolua_set_cItem_m_ItemType); tolua_variable(tolua_S,"m_ItemCount",tolua_get_cItem_m_ItemCount,tolua_set_cItem_m_ItemCount); tolua_variable(tolua_S,"m_ItemDamage",tolua_get_cItem_m_ItemDamage,tolua_set_cItem_m_ItemDamage); diff --git a/source/Bindings.h b/source/Bindings.h index b1c0d55cb..c0e1f288c 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/09/13 19:50:08. +** Generated automatically by tolua++-1.0.92 on 11/10/13 18:40:47. */ /* Exported function */ diff --git a/source/BlockEntities/DropSpenserEntity.cpp b/source/BlockEntities/DropSpenserEntity.cpp index 25def9999..823ed598f 100644 --- a/source/BlockEntities/DropSpenserEntity.cpp +++ b/source/BlockEntities/DropSpenserEntity.cpp @@ -96,7 +96,7 @@ void cDropSpenserEntity::DropSpense(cChunk & a_Chunk) case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break; case E_META_DROPSPENSER_FACING_ZP: SmokeDir = 7; break; } - m_World->BroadcastSoundParticleEffect(2000, m_PosX * 8, m_PosY * 8, m_PosZ * 8, SmokeDir); + m_World->BroadcastSoundParticleEffect(2000, m_PosX, m_PosY, m_PosZ, SmokeDir); m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.0f); // Update the UI window, if open: diff --git a/source/BlockEntities/JukeboxEntity.cpp b/source/BlockEntities/JukeboxEntity.cpp index ec6d13282..1288719f6 100644 --- a/source/BlockEntities/JukeboxEntity.cpp +++ b/source/BlockEntities/JukeboxEntity.cpp @@ -57,7 +57,7 @@ void cJukeboxEntity::UsedBy(cPlayer * a_Player) void cJukeboxEntity::PlayRecord( void ) { - m_World->BroadcastSoundParticleEffect(1005, m_PosX * 8, m_PosY * 8, m_PosZ * 8, m_Record); + m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, m_Record); } @@ -68,8 +68,8 @@ void cJukeboxEntity::EjectRecord( void ) { cItems Drops; Drops.push_back(cItem(m_Record, 1, 0)); - m_World->SpawnItemPickups(Drops, m_PosX, m_PosY+1, m_PosZ); - m_World->BroadcastSoundParticleEffect(1005, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 0); + m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8); + m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0); } diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 7193094d8..f8949577e 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -649,20 +649,25 @@ public: g_BlockSpreadLightFalloff[E_BLOCK_WATER] = 3; // Transparent blocks - g_BlockTransparent[E_BLOCK_AIR] = true; g_BlockTransparent[E_BLOCK_ACTIVATOR_RAIL] = true; + g_BlockTransparent[E_BLOCK_AIR] = true; + g_BlockTransparent[E_BLOCK_BIG_FLOWER] = true; g_BlockTransparent[E_BLOCK_BROWN_MUSHROOM] = true; g_BlockTransparent[E_BLOCK_CARROTS] = true; g_BlockTransparent[E_BLOCK_CHEST] = true; g_BlockTransparent[E_BLOCK_COBWEB] = true; g_BlockTransparent[E_BLOCK_CROPS] = true; + g_BlockTransparent[E_BLOCK_DANDELION] = true; g_BlockTransparent[E_BLOCK_DETECTOR_RAIL] = true; g_BlockTransparent[E_BLOCK_FENCE] = true; g_BlockTransparent[E_BLOCK_FENCE_GATE] = true; g_BlockTransparent[E_BLOCK_FIRE] = true; + g_BlockTransparent[E_BLOCK_FLOWER] = true; g_BlockTransparent[E_BLOCK_FLOWER_POT] = true; g_BlockTransparent[E_BLOCK_GLASS] = true; g_BlockTransparent[E_BLOCK_GLASS_PANE] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true; g_BlockTransparent[E_BLOCK_ICE] = true; g_BlockTransparent[E_BLOCK_IRON_DOOR] = true; g_BlockTransparent[E_BLOCK_LAVA] = true; @@ -670,35 +675,37 @@ public: g_BlockTransparent[E_BLOCK_LEVER] = true; g_BlockTransparent[E_BLOCK_MELON_STEM] = true; g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true; + g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true; g_BlockTransparent[E_BLOCK_POTATOES] = true; g_BlockTransparent[E_BLOCK_POWERED_RAIL] = true; g_BlockTransparent[E_BLOCK_PISTON_EXTENSION] = true; g_BlockTransparent[E_BLOCK_PUMPKIN_STEM] = true; g_BlockTransparent[E_BLOCK_RAIL] = true; g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true; - g_BlockTransparent[E_BLOCK_RED_ROSE] = true; g_BlockTransparent[E_BLOCK_SIGN_POST] = true; + g_BlockTransparent[E_BLOCK_SNOW] = true; g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true; g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true; g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true; - g_BlockTransparent[E_BLOCK_SNOW] = true; g_BlockTransparent[E_BLOCK_TALL_GRASS] = true; g_BlockTransparent[E_BLOCK_TORCH] = true; g_BlockTransparent[E_BLOCK_VINES] = true; - g_BlockTransparent[E_BLOCK_WATER] = true; g_BlockTransparent[E_BLOCK_WALLSIGN] = true; + g_BlockTransparent[E_BLOCK_WATER] = true; g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true; g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; - g_BlockTransparent[E_BLOCK_YELLOW_FLOWER] = true; // TODO: Any other transparent blocks? // One hit break blocks g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true; + g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true; g_BlockOneHitDig[E_BLOCK_CARROTS] = true; g_BlockOneHitDig[E_BLOCK_CROPS] = true; + g_BlockOneHitDig[E_BLOCK_DANDELION] = true; g_BlockOneHitDig[E_BLOCK_FIRE] = true; + g_BlockOneHitDig[E_BLOCK_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true; g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true; g_BlockOneHitDig[E_BLOCK_LOCKED_CHEST] = true; @@ -711,23 +718,24 @@ public: g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_ON] = true; g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true; g_BlockOneHitDig[E_BLOCK_RED_MUSHROOM] = true; - g_BlockOneHitDig[E_BLOCK_RED_ROSE] = true; g_BlockOneHitDig[E_BLOCK_REEDS] = true; g_BlockOneHitDig[E_BLOCK_SAPLING] = true; g_BlockOneHitDig[E_BLOCK_TNT] = true; g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true; g_BlockOneHitDig[E_BLOCK_TORCH] = true; - g_BlockOneHitDig[E_BLOCK_YELLOW_FLOWER] = true; // Blocks that breaks when pushed by piston g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true; g_BlockPistonBreakable[E_BLOCK_AIR] = true; g_BlockPistonBreakable[E_BLOCK_BED] = true; + g_BlockPistonBreakable[E_BLOCK_BIG_FLOWER] = true; g_BlockPistonBreakable[E_BLOCK_BROWN_MUSHROOM] = true; g_BlockPistonBreakable[E_BLOCK_COBWEB] = true; g_BlockPistonBreakable[E_BLOCK_CROPS] = true; + g_BlockPistonBreakable[E_BLOCK_DANDELION] = true; g_BlockPistonBreakable[E_BLOCK_DEAD_BUSH] = true; g_BlockPistonBreakable[E_BLOCK_FIRE] = true; + g_BlockPistonBreakable[E_BLOCK_FLOWER] = true; g_BlockPistonBreakable[E_BLOCK_INACTIVE_COMPARATOR] = true; g_BlockPistonBreakable[E_BLOCK_IRON_DOOR] = true; g_BlockPistonBreakable[E_BLOCK_JACK_O_LANTERN] = true; @@ -744,7 +752,6 @@ public: g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_ON] = true; g_BlockPistonBreakable[E_BLOCK_REDSTONE_WIRE] = true; g_BlockPistonBreakable[E_BLOCK_RED_MUSHROOM] = true; - g_BlockPistonBreakable[E_BLOCK_RED_ROSE] = true; g_BlockPistonBreakable[E_BLOCK_REEDS] = true; g_BlockPistonBreakable[E_BLOCK_SNOW] = true; g_BlockPistonBreakable[E_BLOCK_STATIONARY_LAVA] = true; @@ -757,17 +764,19 @@ public: g_BlockPistonBreakable[E_BLOCK_WATER] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; - g_BlockPistonBreakable[E_BLOCK_YELLOW_FLOWER] = true; // Blocks that can be snowed over: g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false; g_BlockIsSnowable[E_BLOCK_AIR] = false; + g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false; g_BlockIsSnowable[E_BLOCK_BROWN_MUSHROOM] = false; g_BlockIsSnowable[E_BLOCK_CACTUS] = false; g_BlockIsSnowable[E_BLOCK_CHEST] = false; g_BlockIsSnowable[E_BLOCK_CROPS] = false; + g_BlockIsSnowable[E_BLOCK_DANDELION] = false; g_BlockIsSnowable[E_BLOCK_FIRE] = false; + g_BlockIsSnowable[E_BLOCK_FLOWER] = false; g_BlockIsSnowable[E_BLOCK_GLASS] = false; g_BlockIsSnowable[E_BLOCK_ICE] = false; g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false; @@ -780,7 +789,6 @@ public: g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_ON] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_WIRE] = false; g_BlockIsSnowable[E_BLOCK_RED_MUSHROOM] = false; - g_BlockIsSnowable[E_BLOCK_RED_ROSE] = false; g_BlockIsSnowable[E_BLOCK_REEDS] = false; g_BlockIsSnowable[E_BLOCK_SAPLING] = false; g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false; @@ -793,7 +801,6 @@ public: g_BlockIsSnowable[E_BLOCK_VINES] = false; g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false; g_BlockIsSnowable[E_BLOCK_WATER] = false; - g_BlockIsSnowable[E_BLOCK_YELLOW_FLOWER] = false; // Blocks that don't drop without a special tool @@ -834,13 +841,16 @@ public: // Nonsolid Blocks: g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_AIR] = false; + g_BlockIsSolid[E_BLOCK_BIG_FLOWER] = false; g_BlockIsSolid[E_BLOCK_BROWN_MUSHROOM] = false; g_BlockIsSolid[E_BLOCK_CARROTS] = false; g_BlockIsSolid[E_BLOCK_COBWEB] = false; g_BlockIsSolid[E_BLOCK_CROPS] = false; + g_BlockIsSolid[E_BLOCK_DANDELION] = false; g_BlockIsSolid[E_BLOCK_DETECTOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_END_PORTAL] = false; g_BlockIsSolid[E_BLOCK_FIRE] = false; + g_BlockIsSolid[E_BLOCK_FLOWER] = false; g_BlockIsSolid[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_LAVA] = false; g_BlockIsSolid[E_BLOCK_LEVER] = false; @@ -856,7 +866,6 @@ public: g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false; g_BlockIsSolid[E_BLOCK_RED_MUSHROOM] = false; - g_BlockIsSolid[E_BLOCK_RED_ROSE] = false; g_BlockIsSolid[E_BLOCK_REEDS] = false; g_BlockIsSolid[E_BLOCK_SAPLING] = false; g_BlockIsSolid[E_BLOCK_SIGN_POST] = false; @@ -874,7 +883,6 @@ public: g_BlockIsSolid[E_BLOCK_WOODEN_BUTTON] = false; g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false; - g_BlockIsSolid[E_BLOCK_YELLOW_FLOWER] = false; // Torch placeable g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true; @@ -922,6 +930,7 @@ public: g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true; g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true; g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true; + g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true; g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true; g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true; diff --git a/source/BlockID.h b/source/BlockID.h index 28725406d..f3cbc46d6 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -3,7 +3,7 @@ // tolua_begin enum ENUM_BLOCK_ID { - E_BLOCK_AIR = 0, + E_BLOCK_AIR = 0, E_BLOCK_STONE = 1, E_BLOCK_GRASS = 2, E_BLOCK_DIRT = 3, @@ -14,7 +14,7 @@ enum ENUM_BLOCK_ID E_BLOCK_WATER = 8, E_BLOCK_STATIONARY_WATER = 9, E_BLOCK_LAVA = 10, - E_BLOCK_STATIONARY_LAVA = 11, + E_BLOCK_STATIONARY_LAVA = 11, E_BLOCK_SAND = 12, E_BLOCK_GRAVEL = 13, E_BLOCK_GOLD_ORE = 14, @@ -40,8 +40,8 @@ enum ENUM_BLOCK_ID E_BLOCK_PISTON_EXTENSION = 34, E_BLOCK_WOOL = 35, E_BLOCK_PISTON_MOVED_BLOCK = 36, - E_BLOCK_YELLOW_FLOWER = 37, - E_BLOCK_RED_ROSE = 38, + E_BLOCK_DANDELION = 37, + E_BLOCK_FLOWER = 38, E_BLOCK_BROWN_MUSHROOM = 39, E_BLOCK_RED_MUSHROOM = 40, E_BLOCK_GOLD_BLOCK = 41, @@ -102,7 +102,7 @@ enum ENUM_BLOCK_ID E_BLOCK_CAKE = 92, E_BLOCK_REDSTONE_REPEATER_OFF = 93, E_BLOCK_REDSTONE_REPEATER_ON = 94, - E_BLOCK_LOCKED_CHEST = 95, + E_BLOCK_STAINED_GLASS = 95, E_BLOCK_TRAPDOOR = 96, E_BLOCK_SILVERFISH_EGG = 97, E_BLOCK_STONE_BRICKS = 98, @@ -170,22 +170,35 @@ enum ENUM_BLOCK_ID E_BLOCK_DROPPER = 158, E_BLOCK_STAINED_CLAY = 159, + E_BLOCK_STAINED_GLASS_PANE = 160, + E_BLOCK_NEW_LEAVES = 161, // Acacia and Dark Oak IDs in Minecraft 1.7.x + E_BLOCK_NEW_LOG = 162, + E_BLOCK_ACACIA_WOOD_STAIRS = 163, + E_BLOCK_DARK_OAK_WOOD_STAIRS = 164, ///////////////////////////////// E_BLOCK_HAY_BALE = 170, E_BLOCK_CARPET = 171, E_BLOCK_HARDENED_CLAY = 172, E_BLOCK_BLOCK_OF_COAL = 173, + E_BLOCK_PACKED_ICE = 174, + E_BLOCK_BIG_FLOWER = 175, // Keep these two as the last values, without a number - they will get their correct number assigned automagically by C++ // IsValidBlock() depends on this E_BLOCK_NUMBER_OF_TYPES, ///< Number of individual (different) blocktypes - E_BLOCK_MAX_TYPE_ID = E_BLOCK_NUMBER_OF_TYPES - 1 ///< Maximum BlockType number used + E_BLOCK_MAX_TYPE_ID = E_BLOCK_NUMBER_OF_TYPES - 1, ///< Maximum BlockType number used + + // Synonym or ID compatibility + + E_BLOCK_YELLOW_FLOWER = E_BLOCK_DANDELION, + E_BLOCK_RED_ROSE = E_BLOCK_FLOWER, + E_BLOCK_LOCKED_CHEST = E_BLOCK_STAINED_GLASS, }; // tolua_end // tolua_begin enum ENUM_ITEM_ID { - E_ITEM_EMPTY = -1, + E_ITEM_EMPTY = -1, E_ITEM_FIRST = 256, // First true item type @@ -343,7 +356,12 @@ enum ENUM_ITEM_ID E_ITEM_NETHER_QUARTZ = 406, E_ITEM_MINECART_WITH_TNT = 407, E_ITEM_MINECART_WITH_HOPPER = 408, - // TODO: Add horse armour/horse paraphernalia + E_ITEM_IRON_HORSE_ARMOR = 417, + E_ITEM_GOLD_HORSE_ARMOR = 418, + E_ITEM_DIAMOND_HORSE_ARMOR = 419, + E_ITEM_LEAD = 420, + E_ITEM_NAME_TAG = 421, + E_ITEM_MINECART_WITH_COMMAND_BLOCK = 422, // Keep these two as the last values of the consecutive list, without a number - they will get their correct number assigned automagically by C++ // IsValidItem() depends on this! @@ -399,12 +417,12 @@ enum E_META_DROPSPENSER_FACING_XP = 5, // E_BLOCK_DOUBLE_STONE_SLAB metas: - E_META_DOUBLE_STONE_SLAB_STONE = 0, - E_META_DOUBLE_STONE_SLAB_SANDSTONE = 1, - E_META_DOUBLE_STONE_SLAB_WOODEN = 2, - E_META_DOUBLE_STONE_SLAB_COBBLESTONE = 3, - E_META_DOUBLE_STONE_SLAB_BRICK = 4, - E_META_DOUBLE_STONE_SLAB_STONE_BRICK = 5, + E_META_DOUBLE_STONE_SLAB_STONE = 0, + E_META_DOUBLE_STONE_SLAB_SANDSTONE = 1, + E_META_DOUBLE_STONE_SLAB_WOODEN = 2, + E_META_DOUBLE_STONE_SLAB_COBBLESTONE = 3, + E_META_DOUBLE_STONE_SLAB_BRICK = 4, + E_META_DOUBLE_STONE_SLAB_STONE_BRICK = 5, E_META_DOUBLE_STONE_SLAB_NETHER_BRICK = 6, E_META_DOUBLE_STONE_SLAB_STONE_SECRET = 7, @@ -448,25 +466,25 @@ enum E_META_SAPLING_JUNGLE = 3, // E_BLOCK_SILVERFISH_EGG metas: - E_META_SILVERFISH_EGG_STONE = 0, + E_META_SILVERFISH_EGG_STONE = 0, E_META_SILVERFISH_EGG_COBBLESTONE = 1, E_META_SILVERFISH_EGG_STONE_BRICK = 2, // E_BLOCK_STONE_SLAB metas: - E_META_STONE_SLAB_STONE = 0, - E_META_STONE_SLAB_SANDSTONE = 1, - E_META_STONE_SLAB_PLANKS = 2, - E_META_STONE_SLAB_COBBLESTONE = 3, - E_META_STONE_SLAB_BRICK = 4, - E_META_STONE_SLAB_STONE_BRICK = 5, + E_META_STONE_SLAB_STONE = 0, + E_META_STONE_SLAB_SANDSTONE = 1, + E_META_STONE_SLAB_PLANKS = 2, + E_META_STONE_SLAB_COBBLESTONE = 3, + E_META_STONE_SLAB_BRICK = 4, + E_META_STONE_SLAB_STONE_BRICK = 5, E_META_STONE_SLAB_NETHER_BRICK = 6, E_META_STONE_SLAB_STONE_SECRET = 7, // E_BLOCK_STONE_BRICKS metas: - E_META_STONE_BRICK_NORMAL = 0, - E_META_STONE_BRICK_MOSSY = 1, - E_META_STONE_BRICK_CRACKED = 2, - E_META_STONE_BRICK_ORNAMENT = 3, + E_META_STONE_BRICK_NORMAL = 0, + E_META_STONE_BRICK_MOSSY = 1, + E_META_STONE_BRICK_CRACKED = 2, + E_META_STONE_BRICK_ORNAMENT = 3, // E_BLOCK_TALL_GRASS metas: E_META_TALL_GRASS_DEAD_SHRUB = 0, @@ -485,16 +503,20 @@ enum E_META_TORCH_ZP = 4, // Torch attached to the ZP side of its block // E_BLOCK_WOODEN_DOUBLE_SLAB metas: - E_META_WOODEN_DOUBLE_SLAB_APPLE = 0, - E_META_WOODEN_DOUBLE_SLAB_CONIFER = 1, - E_META_WOODEN_DOUBLE_SLAB_BIRCH = 2, - E_META_WOODEN_DOUBLE_SLAB_JUNGLE = 3, + E_META_WOODEN_DOUBLE_SLAB_APPLE = 0, + E_META_WOODEN_DOUBLE_SLAB_CONIFER = 1, + E_META_WOODEN_DOUBLE_SLAB_BIRCH = 2, + E_META_WOODEN_DOUBLE_SLAB_JUNGLE = 3, + E_META_WOODEN_DOUBLE_SLAB_ACACIA = 4, + E_META_WOODEN_DOUBLE_SLAB_DARK_OAK = 5, // E_BLOCK_WOODEN_SLAB metas: - E_META_WOODEN_SLAB_APPLE = 0, - E_META_WOODEN_SLAB_CONIFER = 1, - E_META_WOODEN_SLAB_BIRCH = 2, - E_META_WOODEN_SLAB_JUNGLE = 3, + E_META_WOODEN_SLAB_APPLE = 0, + E_META_WOODEN_SLAB_CONIFER = 1, + E_META_WOODEN_SLAB_BIRCH = 2, + E_META_WOODEN_SLAB_JUNGLE = 3, + E_META_WOODEN_SLAB_ACACIA = 4, + E_META_WOODEN_SLAB_DARK_OAK = 5, // E_BLOCK_WOOL metas: E_META_WOOL_WHITE = 0, @@ -549,6 +571,42 @@ enum E_META_STAINED_CLAY_GREEN = 13, E_META_STAINED_CLAY_RED = 14, E_META_STAINED_CLAY_BLACK = 15, + + // E_BLOCK_STAINED_GLASS metas + E_META_STAINED_GLASS_WHITE = 0, + E_META_STAINED_GLASS_ORANGE = 1, + E_META_STAINED_GLASS_MAGENTA = 2, + E_META_STAINED_GLASS_LIGHTBLUE = 3, + E_META_STAINED_GLASS_YELLOW = 4, + E_META_STAINED_GLASS_LIGHTGREEN = 5, + E_META_STAINED_GLASS_PINK = 6, + E_META_STAINED_GLASS_GRAY = 7, + E_META_STAINED_GLASS_LIGHTGRAY = 8, + E_META_STAINED_GLASS_CYAN = 9, + E_META_STAINED_GLASS_PURPLE = 10, + E_META_STAINED_GLASS_BLUE = 11, + E_META_STAINED_GLASS_BROWN = 12, + E_META_STAINED_GLASS_GREEN = 13, + E_META_STAINED_GLASS_RED = 14, + E_META_STAINED_GLASS_BLACK = 15, + + // E_BLOCK_STAINED_GLASS_PANE metas + E_META_STAINED_GLASS_PANE_WHITE = 0, + E_META_STAINED_GLASS_PANE_ORANGE = 1, + E_META_STAINED_GLASS_PANE_MAGENTA = 2, + E_META_STAINED_GLASS_PANE_LIGHTBLUE = 3, + E_META_STAINED_GLASS_PANE_YELLOW = 4, + E_META_STAINED_GLASS_PANE_LIGHTGREEN = 5, + E_META_STAINED_GLASS_PANE_PINK = 6, + E_META_STAINED_GLASS_PANE_GRAY = 7, + E_META_STAINED_GLASS_PANE_LIGHTGRAY = 8, + E_META_STAINED_GLASS_PANE_CYAN = 9, + E_META_STAINED_GLASS_PANE_PURPLE = 10, + E_META_STAINED_GLASS_PANE_BLUE = 11, + E_META_STAINED_GLASS_PANE_BROWN = 12, + E_META_STAINED_GLASS_PANE_GREEN = 13, + E_META_STAINED_GLASS_PANE_RED = 14, + E_META_STAINED_GLASS_PANE_BLACK = 15, // E_BLOCK_SNOW metas: E_META_SNOW_LAYER_ONE = 0, @@ -571,13 +629,39 @@ enum E_META_RAIL_CURVED_ZP_XM = 7, E_META_RAIL_CURVED_ZM_XM = 8, E_META_RAIL_CURVED_ZM_XP = 9, + + //E_BLOCK_NEW_LEAVES metas + E_META_NEW_LEAVES_ACACIA_WOOD = 0, + E_META_NEW_LEAVES_DARK_OAK_WOOD = 1, + + //E_BLOCK_NEW_LOG metas + E_META_NEW_LOG_ACACIA_WOOD = 0, + E_META_NEW_LOG_DARK_OAK_WOOD = 1, + + //E_BLOCK_FLOWER metas + E_META_FLOWER_POPPY = 0, + E_META_FLOWER_BLUE_ORCHID = 1, + E_META_FLOWER_ALLIUM = 2, + E_META_FLOWER_RED_TULIP = 4, + E_META_FLOWER_ORANGE_TULIP = 5, + E_META_FLOWER_WHITE_TULIP = 6, + E_META_FLOWER_PINK_TULIP = 7, + E_META_FLOWER_OXEYE_DAISY = 8, + + //E_BLOCK_BIG_FLOWER metas + E_META_BIG_FLOWER_SUNFLOWER = 0, + E_META_BIG_FLOWER_LILAC = 1, + E_META_BIG_FLOWER_DOUBLE_TALL_GRASS = 2, + E_META_BIG_FLOWER_LARGE_FERN = 3, + E_META_BIG_FLOWER_ROSE_BUSH = 4, + E_META_BIG_FLOWER_PEONY = 5, /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Item metas: // E_ITEM_COAL metas: - E_META_COAL_NORMAL = 0, - E_META_COAL_CHARCOAL = 1, + E_META_COAL_NORMAL = 0, + E_META_COAL_CHARCOAL = 1, // E_ITEM_DYE metas: E_META_DYE_BLACK = 0, @@ -600,6 +684,18 @@ enum // E_ITEM_GOLDEN_APPLE metas: E_META_GOLDEN_APPLE_NORMAL = 0, E_META_GOLDEN_APPLE_ENCHANTED = 1, + + // E_ITEM_RAW_FISH metas: + E_META_RAW_FISH_FISH = 0, + E_META_RAW_FISH_SALMON = 1, + E_META_RAW_FISH_CLOWNFISH = 2, + E_META_RAW_FISH_PUFFERFISH = 3, + + // E_ITEM_COOKED_FISH metas: + E_META_COOKED_FISH_FISH = 0, + E_META_COOKED_FISH_SALMON = 1, + E_META_COOKED_FISH_CLOWNFISH = 2, + E_META_COOKED_FISH_PUFFERFISH = 3, // E_ITEM_MINECART_TRACKS metas: E_META_TRACKS_X = 1, diff --git a/source/BoundingBox.cpp b/source/BoundingBox.cpp index d8a1bc679..02602992e 100644 --- a/source/BoundingBox.cpp +++ b/source/BoundingBox.cpp @@ -243,11 +243,11 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & { // The starting point is inside the bounding box. a_LineCoeff = 0; - a_Face = BLOCK_FACE_YM; // Make it look as the top face was hit, although none really are. + a_Face = BLOCK_FACE_NONE; // No faces hit return true; } - char Face = 0; + char Face = BLOCK_FACE_NONE; double Coeff = Vector3d::NO_INTERSECTION; // Check each individual bbox face for intersection with the line, remember the one with the lowest coeff diff --git a/source/Chunk.cpp b/source/Chunk.cpp index be75eae41..cfdcc783c 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -1679,9 +1679,9 @@ void cChunk::CollectPickupsByPlayer(cPlayer * a_Player) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { - if (!(*itr)->IsPickup()) + if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile())) { - continue; // Only pickups + continue; // Only pickups and projectiles } float DiffX = (float)((*itr)->GetPosX() - PosX ); float DiffY = (float)((*itr)->GetPosY() - PosY ); @@ -1695,7 +1695,14 @@ void cChunk::CollectPickupsByPlayer(cPlayer * a_Player) ); */ MarkDirty(); - (reinterpret_cast<cPickup *>(*itr))->CollectedBy( a_Player ); + if ((*itr)->IsPickup()) + { + (reinterpret_cast<cPickup *>(*itr))->CollectedBy(a_Player); + } + else + { + (reinterpret_cast<cProjectileEntity *>(*itr))->CollectedBy(a_Player); + } } else if (SqrDist < 5 * 5) { diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index d9de24cff..73a16dbb4 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -613,7 +613,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 3548b4035..f8fd4a8b7 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -729,7 +729,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo if (a_OldBlock == E_BLOCK_AIR) { - LOGD("Digged air? wtf?"); + LOGD("Dug air - what the function?"); return; } @@ -738,7 +738,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo // The ItemHandler is also responsible for spawning the pickups BlockHandler(a_OldBlock)->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ); - World->BroadcastSoundParticleEffect(2001, a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, a_OldBlock, this); + World->BroadcastSoundParticleEffect(2001, a_BlockX, a_BlockY, a_BlockZ, a_OldBlock, this); World->DigBlock(a_BlockX, a_BlockY, a_BlockZ); cRoot::Get()->GetPluginManager()->CallHookPlayerBrokenBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); diff --git a/source/Enchantments.cpp b/source/Enchantments.cpp index 0caf4eb11..6b53d0b52 100644 --- a/source/Enchantments.cpp +++ b/source/Enchantments.cpp @@ -1,4 +1,3 @@ - // Enchantments.cpp // Implements the cEnchantments class representing a storage for item enchantments and stored-enchantments @@ -179,6 +178,8 @@ int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName) { enchPunch, "Punch"}, { enchFlame, "Flame"}, { enchInfinity, "Infinity"}, + { enchLuckOfTheSea, "LuckOfTheSea"}, + { enchLure, "Lure"}, } ; for (int i = 0; i < ARRAYCOUNT(EnchantmentNames); i++) { diff --git a/source/Enchantments.h b/source/Enchantments.h index cda743daf..7581b87b5 100644 --- a/source/Enchantments.h +++ b/source/Enchantments.h @@ -1,4 +1,3 @@ - // Enchantments.h // Declares the cEnchantments class representing a storage for item enchantments and stored-enchantments @@ -58,6 +57,8 @@ public: enchPunch = 49, enchFlame = 50, enchInfinity = 51, + enchLuckOfTheSea = 61, + enchLure = 62, } ; /// Creates an empty enchantments container diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp index bc8abd204..f8aae9703 100644 --- a/source/Entities/Pickup.cpp +++ b/source/Entities/Pickup.cpp @@ -31,8 +31,9 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It , m_bCollected( false ) , m_bIsPlayerCreated( IsPlayerCreated ) { - m_MaxHealth = 5; - m_Health = 5; + SetGravity(-10.5f); + SetMaxHealth(5); + SetHealth(5); SetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ); } @@ -145,6 +146,8 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) { m_Item.m_ItemCount -= NumAdded; m_World->BroadcastCollectPickup(*this, *a_Dest); + // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) + m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); if (m_Item.m_ItemCount == 0) { // All of the pickup has been collected, schedule the pickup for destroying diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 1d5532718..c63b9523b 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -371,6 +371,16 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client) +void cProjectileEntity::CollectedBy(cPlayer * a_Dest) +{ + // Overriden in arrow + UNUSED(a_Dest); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cArrowEntity: @@ -378,7 +388,10 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), m_DamageCoeff(2), - m_IsCritical(false) + m_IsCritical(false), + m_Timer(0), + m_bIsCollected(false), + m_HitBlockPos(Vector3i(0, 0, 0)) { SetSpeed(a_Speed); SetMass(0.1); @@ -398,7 +411,10 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), m_PickupState(psInSurvivalOrCreative), m_DamageCoeff(2), - m_IsCritical((a_Force >= 1)) + m_IsCritical((a_Force >= 1)), + m_Timer(0), + m_bIsCollected(false), + m_HitBlockPos(0, 0, 0) { } @@ -424,7 +440,31 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { + if (a_HitFace == BLOCK_FACE_NONE) + { + return; + } + super::OnHitSolidBlock(a_HitPos, a_HitFace); + int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; + + if (a_HitFace != BLOCK_FACE_YP) + { + AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); + } + else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM + { + a_Y--; + } + else + { + a_Y++; + } + + m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); + + // Broadcast arrow hit sound + m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); // Broadcast the position and speed packets before teleporting: BroadcastMovementUpdate(); @@ -439,7 +479,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { - if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer()) + if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) { // Not an entity that interacts with an arrow return; @@ -452,6 +492,9 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) } a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + // Broadcast successful hit sound + m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + Destroy(); } @@ -459,6 +502,67 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +void cArrowEntity::CollectedBy(cPlayer * a_Dest) +{ + if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) + { + int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); + if (NumAdded > 0) // Only play effects if there was space in inventory + { + m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); + // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) + m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_bIsCollected = true; + } + } +} + + + + + +void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + m_Timer += a_Dt; + + if (m_bIsCollected) + { + if (m_Timer > 500.f) // 0.5 seconds + { + Destroy(); + return; + } + } + else if (m_Timer > 1000 * 60 * 5) // 5 minutes + { + Destroy(); + return; + } + + if (m_IsInGround) + { + int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; + int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; + cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); + + if (Chunk == NULL) + { + // Inside an unloaded chunk, abort + return; + } + + if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed? + { + m_IsInGround = false; // Yes, begin simulating physics again + } + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cThrownEggEntity: diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 547aa174e..28dd76935 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -53,6 +53,9 @@ public: /// Called by the physics blocktracer when the entity hits another entity virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {} + /// Called by Chunk when the projectile is eligible for player collection + virtual void CollectedBy(cPlayer * a_Dest); + // tolua_begin /// Returns the kind of the projectile (fast class identification) @@ -153,9 +156,20 @@ protected: /// If true, the arrow deals more damage bool m_IsCritical; + /// Timer for pickup collection animation or five minute timeout + float m_Timer; + + /// If true, the arrow is in the process of being collected - don't go to anyone else + bool m_bIsCollected; + + /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air + Vector3i m_HitBlockPos; + // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void CollectedBy(cPlayer * a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; // tolua_begin } ; diff --git a/source/Item.cpp b/source/Item.cpp index 5e0beb028..25664e4df 100644 --- a/source/Item.cpp +++ b/source/Item.cpp @@ -122,6 +122,15 @@ bool cItem::IsFullStack(void) const +char cItem::GetMaxStackSize(void) const +{ + return ItemHandler(m_ItemType)->GetMaxStackSize(); +} + + + + + /// Returns the cItemHandler responsible for this item type cItemHandler * cItem::GetHandler(void) const { diff --git a/source/Item.h b/source/Item.h index fee861050..c60d0542c 100644 --- a/source/Item.h +++ b/source/Item.h @@ -132,6 +132,9 @@ public: /// Returns true if the item is stacked up to its maximum stacking. bool IsFullStack(void) const; + + /// Returns the maximum amount of stacked items of this type. + char GetMaxStackSize(void) const; // tolua_end diff --git a/source/Items/ItemBow.h b/source/Items/ItemBow.h index 7bce127b1..d533c21fd 100644 --- a/source/Items/ItemBow.h +++ b/source/Items/ItemBow.h @@ -36,6 +36,7 @@ public: { return false; } + a_Player->StartChargingBow(); return true; } @@ -71,6 +72,7 @@ public: 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); if (!a_Player->IsGameModeCreative()) { diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 37274e2af..f98e25880 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -1347,7 +1347,9 @@ static int tolua_cPluginManager_BindCommand(lua_State * L) if (!self->BindCommand(Command, Plugin, Permission, HelpString)) { - // Refused. Possibly already bound. Error message has been given, bail out silently. + // Refused. Possibly already bound. Error message has been given, display the callstack: + cLuaState LS(L); + LS.LogStackTrace(); return 0; } @@ -1409,7 +1411,9 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L) if (!self->BindConsoleCommand(Command, Plugin, HelpString)) { - // Refused. Possibly already bound. Error message has been given, bail out silently. + // Refused. Possibly already bound. Error message has been given, display the callstack: + cLuaState LS(L); + LS.LogStackTrace(); return 0; } diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp index d18887ea4..bb9a4e3f6 100644 --- a/source/Mobs/Horse.cpp +++ b/source/Mobs/Horse.cpp @@ -55,10 +55,10 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk) { if (m_World->GetTickRandomNumber(50) == 25) { - m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 0); - m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 2); - m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 6); - m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 8); + m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 0); + m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 2); + m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 6); + m_World->BroadcastSoundParticleEffect(2000, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ(), 8); m_Attachee->Detach(); m_bIsRearing = true; diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 9d2be1e29..8a5717e27 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -622,65 +622,78 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) -cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType, int a_Size) +cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) { cFastRandom Random; - cMonster * toReturn = NULL; - // unspecified size get rand[1,3] for Monsters that need size + // Create the mob entity switch (a_MobType) { case mtMagmaCube: case mtSlime: { - if (a_Size == -1) + toReturn = new cSlime (Random.NextInt(2) + 1); + break; + } + case mtSkeleton: + { + // TODO: Actual detection of spawning in Nether + toReturn = new cSkeleton(Random.NextInt(1) == 0 ? false : true); + break; + } + case mtVillager: + { + int VillagerType = Random.NextInt(6); + if (VillagerType == 6) { - a_Size = Random.NextInt(2, a_MobType) + 1; + // Give farmers a better chance of spawning + VillagerType = 0; } - if ((a_Size <= 0) || (a_Size >= 4)) + + toReturn = new cVillager((cVillager::eVillagerType)VillagerType); + break; + } + case mtHorse: + { + // Horses take a type (species), a colour, and a style (dots, stripes, etc.) + int HorseType = Random.NextInt(7); + int HorseColor = Random.NextInt(6); + int HorseStyle = Random.NextInt(6); + int HorseTameTimes = Random.NextInt(6) + 1; + + if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7)) { - ASSERT(!"Random for size was supposed to pick in [1..3] and picked outside"); - a_Size = 1; + // Increase chances of normal horse (zero) + HorseType = 0; } + + toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes); break; } - default: break; - } // switch (a_MobType) - // Create the mob entity - switch (a_MobType) - { - case mtMagmaCube: toReturn = new cMagmaCube(a_Size); break; - case mtSlime: toReturn = new cSlime(a_Size); break; - case mtBat: toReturn = new cBat(); break; - case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCavespider(); break; - case mtChicken: toReturn = new cChicken(); break; - case mtCow: toReturn = new cCow(); break; - case mtCreeper: toReturn = new cCreeper(); break; - case mtEnderman: toReturn = new cEnderman(); break; - case mtGhast: toReturn = new cGhast(); break; - // TODO: - // case cMonster::mtHorse: toReturn = new cHorse(); break; - case mtMooshroom: toReturn = new cMooshroom(); break; - case mtOcelot: toReturn = new cOcelot(); break; - case mtPig: toReturn = new cPig(); break; - // TODO: Implement sheep color - case mtSheep: toReturn = new cSheep(0); break; - case mtSilverfish: toReturn = new cSilverfish(); break; - // TODO: Implement wither skeleton geration - case mtSkeleton: toReturn = new cSkeleton(false); break; - case mtSpider: toReturn = new cSpider(); break; - case mtSquid: toReturn = new cSquid(); break; - case mtVillager: toReturn = new cVillager(cVillager::vtFarmer); break; - case mtWitch: toReturn = new cWitch(); break; - case mtWolf: toReturn = new cWolf(); break; - case mtZombie: toReturn = new cZombie(false); break; - case mtZombiePigman: toReturn = new cZombiePigman(); break; + case mtBat: toReturn = new cBat(); break; + case mtBlaze: toReturn = new cBlaze(); break; + case mtCaveSpider: toReturn = new cCavespider(); break; + case mtChicken: toReturn = new cChicken(); break; + case mtCow: toReturn = new cCow(); break; + case mtCreeper: toReturn = new cCreeper(); break; + case mtEnderman: toReturn = new cEnderman(); break; + case mtGhast: toReturn = new cGhast(); break; + case mtMooshroom: toReturn = new cMooshroom(); break; + case mtOcelot: toReturn = new cOcelot(); break; + case mtPig: toReturn = new cPig(); break; + case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter + case mtSilverfish: toReturn = new cSilverfish(); break; + case mtSpider: toReturn = new cSpider(); break; + case mtSquid: toReturn = new cSquid(); break; + case mtWitch: toReturn = new cWitch(); break; + case mtWolf: toReturn = new cWolf(); break; + case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter + case mtZombiePigman: toReturn = new cZombiePigman(); break; default: { - ASSERT(!"Unhandled Mob type"); + ASSERT(!"Unhandled mob type whilst trying to spawn mob!"); } } return toReturn; diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index a0002bf4f..29a705d11 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -153,12 +153,9 @@ public: /** Creates a new object of the specified mob. a_MobType is the type of the mob to be created - a_Size is the size (for mobs with size) - if a_Size is let to -1 for entities that need size, size will be random - asserts and returns null if mob type is not specified - asserts if invalid size for mobs that need size + Asserts and returns null if mob type is not specified */ - static cMonster * NewMonsterFromType(eType a_MobType, int a_Size = -1); + static cMonster * NewMonsterFromType(eType a_MobType); protected: diff --git a/source/Mobs/Sheep.cpp b/source/Mobs/Sheep.cpp index 703482ddb..bda4ccff8 100644 --- a/source/Mobs/Sheep.cpp +++ b/source/Mobs/Sheep.cpp @@ -33,7 +33,6 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) - void cSheep::OnRightClicked(cPlayer & a_Player) { if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared)) @@ -51,9 +50,13 @@ void cSheep::OnRightClicked(cPlayer & a_Player) Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor)); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); } + if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - a_Player.GetEquippedItem().m_ItemDamage)) + { + m_WoolColor = 15 - a_Player.GetEquippedItem().m_ItemDamage; + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + m_World->BroadcastEntityMetadata(*this); + } } - - - - - diff --git a/source/Mobs/Wolf.cpp b/source/Mobs/Wolf.cpp index c6e9736f5..c86250142 100644 --- a/source/Mobs/Wolf.cpp +++ b/source/Mobs/Wolf.cpp @@ -182,4 +182,8 @@ void cWolf::TickFollowPlayer() m_Destination = Callback.OwnerPos; } } -}
\ No newline at end of file +} + + + + diff --git a/source/Mobs/Wolf.h b/source/Mobs/Wolf.h index faae1d7af..040e2cf7a 100644 --- a/source/Mobs/Wolf.h +++ b/source/Mobs/Wolf.h @@ -41,12 +41,12 @@ public: protected: - bool m_IsSitting; - bool m_IsTame; - bool m_IsBegging; - bool m_IsAngry; - AString m_OwnerName; - int m_CollarColor; + bool m_IsSitting; + bool m_IsTame; + bool m_IsBegging; + bool m_IsAngry; + AString m_OwnerName; + int m_CollarColor; } ; diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 3ac2366ca..c1f695163 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -1511,11 +1511,11 @@ bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_P { if (cmd->second.m_Plugin == NULL) { - LOGWARNING("Console command \"%s\" is already bound internally by MCServer.", a_Command.c_str()); + LOGWARNING("Console command \"%s\" is already bound internally by MCServer, cannot bind in plugin \"%s\".", a_Command.c_str(), a_Plugin->GetName().c_str()); } else { - LOGWARNING("Console command \"%s\" is already bound to plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str()); + LOGWARNING("Console command \"%s\" is already bound to plugin \"%s\", cannot bind in plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str(), a_Plugin->GetName().c_str()); } return false; } diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp index 53159a3b3..22eac4312 100644 --- a/source/Protocol/Protocol132.cpp +++ b/source/Protocol/Protocol132.cpp @@ -392,9 +392,9 @@ void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src cCSLock Lock(m_CSPacket); WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); - WriteInt (a_SrcX / 8); - WriteByte(a_SrcY / 8); - WriteInt (a_SrcZ / 8); + WriteInt (a_SrcX); + WriteByte(a_SrcY); + WriteInt (a_SrcZ); WriteInt (a_Data); Flush(); } diff --git a/source/Protocol/Protocol14x.cpp b/source/Protocol/Protocol14x.cpp index ba9d7c01a..d2582458b 100644 --- a/source/Protocol/Protocol14x.cpp +++ b/source/Protocol/Protocol14x.cpp @@ -109,9 +109,9 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src cCSLock Lock(m_CSPacket); WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); - WriteInt (a_SrcX / 8); - WriteByte(a_SrcY / 8); - WriteInt (a_SrcZ / 8); + WriteInt (a_SrcX); + WriteByte(a_SrcY); + WriteInt (a_SrcZ); WriteInt (a_Data); WriteBool(0); Flush(); diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index 5022d6dbc..628b8e071 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -17,6 +17,7 @@ Implements the 1.7.x protocol classes: #include "../World.h" #include "../WorldStorage/FastNBT.h" #include "../StringCompression.h" +#include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" #include "../Entities/Pickup.h" #include "../Entities/Player.h" @@ -215,7 +216,7 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity) void cProtocol172::SendDisconnect(const AString & a_Reason) { cPacketizer Pkt(*this, 0x40); - Pkt.WriteString(a_Reason); + Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); } @@ -503,7 +504,7 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) cPacketizer Pkt(*this, 0x38); // Playerlist Item packet Pkt.WriteString(a_Player.GetName()); Pkt.WriteBool(a_IsOnline); - Pkt.WriteShort(a_Player.GetClientHandle()->GetPing()); + Pkt.WriteShort(a_IsOnline ? a_Player.GetClientHandle()->GetPing() : 0); } @@ -564,7 +565,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) { // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet - Pkt.WriteInt(a_Player.GetUniqueID()); + Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID Pkt.WriteString(a_Player.GetName()); Pkt.WriteFPInt(a_Player.GetPosX()); @@ -615,9 +616,9 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src { cPacketizer Pkt(*this, 0x28); // Effect packet Pkt.WriteInt(a_EffectID); - Pkt.WriteInt(a_SrcX / 8); - Pkt.WriteByte(a_SrcY / 8); - Pkt.WriteInt(a_SrcZ / 8); + Pkt.WriteInt(a_SrcX); + Pkt.WriteByte(a_SrcY); + Pkt.WriteInt(a_SrcZ); Pkt.WriteInt(a_Data); Pkt.WriteBool(false); } @@ -819,9 +820,13 @@ void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc void cProtocol172::SendWeather(eWeather a_Weather) { - cPacketizer Pkt(*this, 0x2b); // Change Game State packet - Pkt.WriteByte((a_Weather == wSunny) ? 2 : 1); // begin rain / end rain - Pkt.WriteFloat(0); // unused + { + cPacketizer Pkt(*this, 0x2b); // Change Game State packet + Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain + Pkt.WriteFloat(0); // Unused for weather + } + + // TODO: Fade effect, somehow } @@ -1664,12 +1669,43 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteItem(((const cPickup &)a_Entity).GetItem()); break; } + case cEntity::etMinecart: + { + WriteByte(0x51); + + // The following expression makes Minecarts shake more with less health or higher damage taken + // It gets half the maximum health, and takes it away from the current health minus the half health: + /* Health: 5 | 3 - (5 - 3) = 1 (shake power) + Health: 3 | 3 - (3 - 3) = 3 + Health: 1 | 3 - (1 - 3) = 5 + */ + WriteInt((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4); + WriteByte(0x52); + WriteInt(1); // Shaking direction, doesn't seem to affect anything + WriteByte(0x73); + WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer + + if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) + { + WriteByte(0x10); + WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0); + } + break; + } + case cEntity::etProjectile: + { + if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow) + { + WriteByte(0x10); + WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); + } + break; + } case cEntity::etMonster: { WriteMobMetadata((const cMonster &)a_Entity); break; } - // TODO: Other types } } diff --git a/source/Root.cpp b/source/Root.cpp index 4760c3ef1..701832be7 100644 --- a/source/Root.cpp +++ b/source/Root.cpp @@ -547,9 +547,9 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac } if (Rating == NameLength) // Perfect match { - return false; + return true; } - return true; + return false; } public: diff --git a/source/Server.cpp b/source/Server.cpp index 75ce35cb7..fe8076631 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -462,6 +462,18 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac return; } + // "help" and "reload" are to be handled by MCS, so that they work no matter what + if (split[0] == "help") + { + PrintHelp(split, a_Output); + return; + } + if (split[0] == "reload") + { + cPluginManager::Get()->ReloadPlugins(); + return; + } + // There is currently no way a plugin can do these (and probably won't ever be): if (split[0].compare("chunkstats") == 0) { @@ -500,9 +512,52 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac +void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output) +{ + typedef std::pair<AString, AString> AStringPair; + typedef std::vector<AStringPair> AStringPairs; + + class cCallback : + public cPluginManager::cCommandEnumCallback + { + public: + cCallback(void) : m_MaxLen(0) {} + + virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override + { + if (!a_HelpString.empty()) + { + m_Commands.push_back(AStringPair(a_Command, a_HelpString)); + if (m_MaxLen < a_Command.length()) + { + m_MaxLen = a_Command.length(); + } + } + return false; + } + + AStringPairs m_Commands; + size_t m_MaxLen; + } Callback; + cPluginManager::Get()->ForEachConsoleCommand(Callback); + std::sort(Callback.m_Commands.begin(), Callback.m_Commands.end()); + for (AStringPairs::const_iterator itr = Callback.m_Commands.begin(), end = Callback.m_Commands.end(); itr != end; ++itr) + { + const AStringPair & cmd = *itr; + a_Output.Out(Printf("%-*s%s\n", Callback.m_MaxLen, cmd.first.c_str(), cmd.second.c_str())); + } // for itr - Callback.m_Commands[] + a_Output.Finished(); +} + + + + + void cServer::BindBuiltInConsoleCommands(void) { cPluginManager * PlgMgr = cPluginManager::Get(); + PlgMgr->BindConsoleCommand("help", NULL, " - Shows the available commands"); + PlgMgr->BindConsoleCommand("reload", NULL, " - Reloads all plugins"); PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly"); PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly"); PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics"); diff --git a/source/Server.h b/source/Server.h index 6742153ac..1b4848318 100644 --- a/source/Server.h +++ b/source/Server.h @@ -57,6 +57,9 @@ public: // tolua_export /// Executes the console command, sends output through the specified callback void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output); + + /// Lists all available console commands and their helpstrings + void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output); /// Binds the built-in console commands with the plugin manager static void BindBuiltInConsoleCommands(void); diff --git a/source/Simulator/FloodyFluidSimulator.cpp b/source/Simulator/FloodyFluidSimulator.cpp index 9374bbab3..d204a1f8b 100644 --- a/source/Simulator/FloodyFluidSimulator.cpp +++ b/source/Simulator/FloodyFluidSimulator.cpp @@ -224,9 +224,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ItemTypeToString(NewBlock).c_str() ); a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - - // TODO: Sound effect - + m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f); return; } } @@ -240,9 +238,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i a_RelX, a_RelY, a_RelZ, ItemTypeToString(NewBlock).c_str() ); a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - - // TODO: Sound effect - + m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f); return; } } diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 82e87e126..7fd7cd996 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -50,15 +50,20 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA return; } - if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + switch (a_ClickAction) { - if (!a_Player.IsDraggingItem()) + case caShiftLeftClick: + case caShiftRightClick: { ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); return; } - LOGD("Shift clicked, but the player is dragging an item: %s", ItemToFullString(a_Player.GetDraggingItem()).c_str()); - return; + + case caDblClick: + { + DblClicked(a_Player, a_SlotNum); + return; + } } cItem Slot(*GetSlot(a_SlotNum, a_Player)); @@ -182,6 +187,36 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ +void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + cItem & Dragging = a_Player.GetDraggingItem(); + if (Dragging.IsEmpty()) + { + // Move the item in the dblclicked slot into hand: + Dragging = *GetSlot(a_SlotNum, a_Player); + cItem EmptyItem; + SetSlot(a_SlotNum, a_Player, EmptyItem); + } + if (Dragging.IsEmpty()) + { + LOGD("%s DblClicked with an empty hand over empty slot, ignoring", a_Player.GetName().c_str()); + return; + } + + // Add as many items from the surrounding area into hand as possible: + // First skip full stacks, then if there's still space, process full stacks as well: + if (!m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, false)) + { + m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, true); + } + + m_ParentWindow.BroadcastWholeWindow(); // We need to broadcast, in case the window was a chest opened by multiple players +} + + + + + void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) { for (int i = 0; i < m_NumSlots; i++) @@ -220,6 +255,39 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ +bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks) +{ + int NumSlots = GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + const cItem & SlotItem = *GetSlot(i, a_Player); + if (!SlotItem.IsStackableWith(a_Dragging)) + { + continue; + } + int ToMove = a_Dragging.GetMaxStackSize() - a_Dragging.m_ItemCount; + if (ToMove > SlotItem.m_ItemCount) + { + ToMove = SlotItem.m_ItemCount; + } + a_Dragging.m_ItemCount += ToMove; + cItem NewSlot(SlotItem); + NewSlot.m_ItemCount -= ToMove; + SetSlot(i, a_Player, NewSlot); + if (!NewSlot.IsEmpty()) + { + // There are leftovers in the slot, so a_Dragging must be full + return true; + } + } // for i - Slots[] + // a_Dragging may be full if there were exactly the number of items needed to fill it + return a_Dragging.IsFullStack(); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaChest: @@ -336,6 +404,20 @@ void cSlotAreaCrafting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction +void cSlotAreaCrafting::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + if (a_SlotNum == 0) + { + // Dbl-clicking the crafting result slot shouldn't collect items to hand + return; + } + super::DblClicked(a_Player, a_SlotNum); +} + + + + + void cSlotAreaCrafting::OnPlayerRemoved(cPlayer & a_Player) { // Toss all items on the crafting grid: diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h index 943452feb..b1944d901 100644 --- a/source/UI/SlotArea.h +++ b/source/UI/SlotArea.h @@ -40,9 +40,12 @@ public: /// Called when a player clicks in the window. Parameters taken from the click packet. virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem); - /// Called from Clicked if it is a valid shiftclick + /// Called from Clicked when the action is a shiftclick (left or right) virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem); + /// Called from Clicked when the action is a caDblClick + virtual void DblClicked(cPlayer & a_Player, int a_SlotNum); + /// Called when a new player opens the same parent window. The window already tracks the player. CS-locked. virtual void OnPlayerAdded(cPlayer & a_Player) {} ; @@ -57,6 +60,12 @@ public: */ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots); + /// Called on DblClicking to collect all stackable items into hand. + /// The items are accumulated in a_Dragging and removed from the slots immediately. + /// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting. + /// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill. + virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks); + protected: int m_NumSlots; cWindow & m_ParentWindow; @@ -212,6 +221,7 @@ public: // cSlotAreaTemporary overrides: virtual void Clicked (cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DblClicked (cPlayer & a_Player, int a_SlotNum); virtual void OnPlayerRemoved(cPlayer & a_Player) override; // Distributing items into this area is completely disabled diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 1f023cb03..f5c62692f 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -386,6 +386,51 @@ void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea +bool cWindow::CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks) +{ + // First ask the slot areas from a_Area till the end of list: + bool ShouldCollect = false; + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (&a_Area == *itr) + { + ShouldCollect = true; + } + if (!ShouldCollect) + { + continue; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + + // a_Dragging still not full, ask slot areas before a_Area in the list: + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (*itr == &a_Area) + { + // All areas processed + return false; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + // Shouldn't reach here + // a_Area is expected to be part of m_SlotAreas[], so the "return false" in the loop above should have returned already + ASSERT(!"This branch should not be reached"); + return false; +} + + + + + void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) { int SlotBase = 0; @@ -583,7 +628,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int // Modify the item at the slot cItem AtSlot(*Area->GetSlot(LocalSlotNum, a_Player)); - int MaxStack = ItemHandler(AtSlot.m_ItemType)->GetMaxStackSize(); + int MaxStack = AtSlot.GetMaxStackSize(); if (AtSlot.IsEmpty()) { // Empty, just move all of it there: @@ -592,7 +637,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int Area->SetSlot(LocalSlotNum, a_Player, ToStore); NumDistributed += ToStore.m_ItemCount; } - else + else if (AtSlot.IsStackableWith(a_Item)) { // Occupied, add and cap at MaxStack: int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount); diff --git a/source/UI/Window.h b/source/UI/Window.h index 6927cd3ac..c44b900d7 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -156,6 +156,12 @@ public: */ void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + /// Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area. + /// The items are accumulated in a_Dragging and removed from the SlotAreas immediately. + /// If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting. + /// Returns true if full stack has been collected, false if there's space remaining to fill. + bool CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks); + /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum); diff --git a/source/World.cpp b/source/World.cpp index c6bc47be5..0f9df8a62 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -1512,7 +1512,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr) { float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500)); - float SpeedY = 1; + float SpeedY = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500)); float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(1000) - 500)); cPickup * Pickup = new cPickup( @@ -2563,15 +2563,16 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) { cMonster * Monster = NULL; - - int ShColor = GetTickRandomNumber(15); // 0 .. 15 - Sheep - bool SkType = GetDimension() == dimNether ; // Skeleton Monster = cMonster::NewMonsterFromType(a_MonsterType); if (Monster != NULL) { Monster->SetPosition(a_PosX, a_PosY, a_PosZ); } + + // Because it's logical that ALL mob spawns need spawn effects, not just spawners + BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0); + return SpawnMobFinalize(Monster); } |